Java程序的输出 |第 10 组(垃圾收集)
先决条件 - Java中的垃圾收集
难度级别:中级
在Java中,垃圾收集器模块负责对象销毁,并且没有对它们的任何引用的对象有资格进行垃圾收集。以下是有关垃圾收集的一些重要输出问题。
预测以下Java程序的输出:
- 程序 1:
public class Test { public static void main(String[] args) throws InterruptedException { String str = new String("GeeksForGeeks"); // making str eligible for gc str = null; // calling garbage collector System.gc(); // waiting for gc to complete Thread.sleep(1000); System.out.println("end of main"); } @Override protected void finalize() { System.out.println("finalize method called"); } }
输出:
end of main
解释:我们知道垃圾收集器在销毁对象之前会调用 finalize() 方法。但在这里,诀窍在于 str 是 String 类对象,而不是 Test 类。因此,在 str 上调用 String 类的 finalize() 方法(如果在 String 类中被覆盖)。如果一个类没有覆盖 finalize 方法,则默认调用 Object 类的 finalize() 方法。
- 方案二:
public class Test { public static void main(String[] args) throws InterruptedException { Test t = new Test(); // making t eligible for garbage collection t = null; // calling garbage collector System.gc(); // waiting for gc to complete Thread.sleep(1000); System.out.println("end main"); } @Override protected void finalize() { System.out.println("finalize method called"); System.out.println(10/0); } }
输出:
finalize method called end main
解释 :
当垃圾收集器在对象上调用 finalize() 方法时,它会忽略该方法中引发的所有异常,程序将正常终止。 - 程序 3:
public class Test { static Test t ; static int count =0; public static void main(String[] args) throws InterruptedException { Test t1 = new Test(); // making t1 eligible for garbage collection t1 = null; // line 12 // calling garbage collector System.gc(); // line 15 // waiting for gc to complete Thread.sleep(1000); // making t eligible for garbage collection, t = null; // line 21 // calling garbage collector System.gc(); // line 24 // waiting for gc to complete Thread.sleep(1000); System.out.println("finalize method called "+count+" times"); } @Override protected void finalize() { count++; t = this; // line 38 } }
输出:
finalize method called 1 times
解释 :
执行第 12 行后,t1 就可以进行垃圾回收了。所以当我们在第 15 行调用垃圾收集器时,垃圾收集器会在销毁 t1 之前调用 finalize() 方法。但是在 finalize 方法中,在第 38 行,我们再次通过 t 引用同一个对象,因此在执行第 38 行之后,该对象不再符合垃圾回收条件。因此,垃圾收集器不会销毁对象。现在再次在第 21 行,我们让同一个对象再次符合垃圾回收的条件。在这里,我们必须清楚关于垃圾收集器的一个事实,即它会在特定对象上调用 finalize() 方法恰好一次。由于在这个对象上已经调用了 finalize() 方法,所以现在垃圾收集器将销毁它,而无需再次调用 finalize() 方法。
- 程序 4:
public class Test { public static void main(String[] args) { // How many objects are eligible for // garbage collection after this line? m1(); // Line 5 } static void m1() { Test t1 = new Test(); Test t2 = new Test(); } }
问题 :
执行第 5 行后有多少对象符合垃圾回收条件?
回答 :2
解释 :
由于 t1 和 t2 是 m1() 方法的本地对象,因此它们在方法执行完成后才有资格进行垃圾回收,除非它们中的任何一个被返回。 - 方案 5:
public class Test { public static void main(String [] args) { Test t1 = new Test(); Test t2 = m1(t1); // line 6 Test t3 = new Test(); t2 = t3; // line 8 } static Test m1(Test temp) { temp = new Test(); return temp; } }
问题 :
执行第 8 行后有多少对象符合垃圾回收条件?
回答 :1
解释 :
到第 8 行执行时,唯一没有引用的对象是第 6 行生成的对象。请记住“Java严格按值传递”,因此引用变量 t1 不受 m1() 方法的影响.我们可以使用 finalize() 方法检查它。 finalize() 方法中的语句“System.out.println(this.hashcode())”打印调用 finalize() 方法的对象 hashcode 值,然后将该值与 main 方法中创建的其他对象 hashcode 值进行比较.