And*_*anu 18 java garbage-collection
提供以下代码:
class A {
Boolean b;
A easyMethod(A a){
a = null;
return a;
}
public static void main(String [] args){
A a1 = new A();
A a2 = new A();
A a3 = new A();
a3 = a1.easyMethod(a2);
a1 = null;
// Some other code
}
}
Run Code Online (Sandbox Code Playgroud)
问题是之前有多少对象符合垃圾收集的条件// Some other code.
然后正确答案是(至少那是面试官的答案):2 - 布尔值,b因为它是一个包装器和a1.
你能帮我解释一下为什么a2而a3不是垃圾收集?
后期编辑:
谢谢你的回答,我会在那之后发一些面试反馈:).
cor*_*iKa 19
假设go它应该是easyMethod这样的
class A {
Boolean b;
A easyMethod(A a){
a = null; // the reference to a2 was passed in, but is set to null
// a2 is not set to null - this copy of a reference is!
return a; // null is returned
}
public static void main(String [] args){
A a1 = new A(); // 1 obj
A a2 = new A(); // 2 obj
A a3 = new A(); // 3 obj
a3 = a1.go(a2); // a3 set to null and flagged for GC - see above for why
a1 = null; // so far, a1 and a3 have been set to null and flagged
// Some other code
}
}
Run Code Online (Sandbox Code Playgroud)
两个对象有资格进行垃圾回收(a1和a3).b不是因为它只是对null的引用.没有Boolean做过.
为了解决// Some other code可能存在的愚蠢微妙之处,我将问题重新改写为以下内容:
判定并解释以下输出:
class A {
int i;
A(int i) { this.i = i; }
public String toString() { return ""+i; }
A go(A a){
a = null; // the reference to a2 was passed in, but is set to null
// a2 is not set to null - this copy of a reference is!
return a; // null is returned
}
public static void main(String [] args){
A a1 = new A(1); // 1 obj
A a2 = new A(2); // 2 obj
A a3 = new A(3); // 3 obj
a3 = a1.go(a2); // a3 set to null and flagged for GC - see above for why
a1 = null; // so far, a1 and a3 have been set to null and flagged
test(a1);
test(a2);
test(a3);
}
static void test(A a) {
try { System.out.println(a); }
catch(Exception e) { System.out.println((String)null); }
}
}
Run Code Online (Sandbox Code Playgroud)
并输出:
c:\files\j>javac A.java
c:\files\j>java A
null
2
null
Run Code Online (Sandbox Code Playgroud)
后续的是,那时a1和a3符合GC的条件,而a2则没有.
这个问题的教训是"将对象引用传递给方法并将该引用设置为null不会导致原始引用为空".这是面试官试图测试的知识.
提供的a1.go(a2)实际意思是a1.easyMethod(a2),答案确实是2,而不是你列出的.正如Bozho正确指出的那样,b没有初始化,所以它没有提到任何对象.在注释点有资格进行垃圾收集的两个对象是最初由a1和引用的对象a3.
a1显然是无效的,并被a3重新分配给返回值a1.easyMethod(a2),该值为null.但是,a2不受方法调用的影响,因为Java是按值传递的,因此只有引用的副本a2传递给方法.即使副本设置为null,也不会影响原始值a2.
对于a2的原始拒绝,它实际上完全取决于"其他一些代码"中发生的事情.如果"某些其他代码"不使用a2或a3,则原始a2对象可以进行垃圾回收.
那是因为运行时不必关心词法范围.它只需要知道永远不能再引用一个对象.因此,如果"某些其他代码"不使用a2或a3,则它们指向的对象永远不会再次引用,因此已经可用于垃圾回收.
首先,访谈者对布尔值是错误的 - 这个代码没有创建这样的对象,所以没有什么可以被垃圾收集.
这是不正确的说话的变量一样b,并a2为垃圾收集.对象是垃圾收集的,而不是变量.如果范围内变量引用了对象,则无法对其进行垃圾回收.简单地说,只有当一个对象不再被任何变量引用时,它才能被垃圾收集.
因此,我们在此代码中创建了三个A实例.它们开始引用a1等等,但由于变量引用更改,我将对象实例称为A1,A2和A3.由于你没有显示go方法的定义,我将假设它是一个调用easyMethod.
由于变量a1被重新赋值为null,因此没有任何内容指向实例A1,因此可以对其进行垃圾回收.
由于变量a2永远不会被重新分配(赋值in easyMethod不影响原始变量),因此不能对实例A2进行垃圾回收.
由于easyMethod始终返回null并且a3被赋予该方法的结果,因此没有任何东西指向实例A3,因此它也可以被垃圾收集.