Дайте следующий код:
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
}
}
Вопрос состоит в том, сколько объектов имеет право на сборку "мусора" прямо прежде // Some other code
.
Затем корректный ответ (по крайней мере это - ответ интервьюера): 2 - булевская переменная b
потому что это - обертка и a1
.
Можно ли понравиться мне, объясняют меня почему a2
и a3
разве существо не собрано "мусор"?
БОЛЕЕ ПОЗДНЕЕ РЕДАКТИРОВАНИЕ:
Спасибо за ответ я отправлю некоторый отклик интервью после этого :).
Предполагая, что 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
}
}
Два объекта имеют право на сборку мусора (a1 и a3). b
не потому, что это всего лишь ссылка на null. Логическое значение
никогда не создавалось.
Чтобы обойти бессмысленные тонкости того, что // может быть другим кодом
, я вместо этого предлагаю переформулировать вопрос следующим образом:
Prdict и поясняю следующий результат:
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); }
}
}
И вывод:
c:\files\j>javac A.java
c:\files\j>java A
null
2
null
Далее следует, что на тот момент a1 и a3 имели право на сборку мусора, а a2 - нет.
Урок из этого вопроса состоит в том, что «Передача ссылки на объект методу и установка этой ссылки на null не приводит к обнулению исходной ссылки». Это знание, которое интервьюер пытался проверить.
Для исходного референта a2 это фактически полностью зависит от того, что происходит в «каком-то другом коде». Если «какой-то другой код» не использует a2 или a3, то исходный объект a2 имеет право на сборку мусора.
Это потому, что среда выполнения не должна заботиться о лексической области видимости. Ему просто нужно знать, что на объект больше нельзя ссылаться. Следовательно, если «какой-то другой код» не использует a2 или a3, объект, на который они указывают , больше никогда не сможет ссылаться , и поэтому уже доступен для сборки мусора.
При условии, что a1.go(a2)
на самом деле должно быть a1.easyMethod(a2)
, ответ действительно 2, но не те, которые вы перечислили. Как верно заметил Божо, b
не инициализирован, поэтому он не ссылается ни на какой объект. Два объекта, подлежащие сборке мусора в момент комментария, это объекты, на которые изначально ссылаются a1
и a3
.
a1
, очевидно, обнуляется, а a3
переназначается на возвращаемое значение a1.easyMethod(a2)
, которое равно нулю. Однако вызов метода не затрагивает a2
, поскольку Java передает по значению, поэтому в метод передается только копия ссылки a2
. Даже если копия установлена в null, это не влияет на значение исходной a2
.
Прежде всего, интервьюер ошибается насчет логического значения - этот код не создает такого объекта, поэтому собирать мусор нечего.
Неверно говорить о переменных , таких как b
и a2
, как о собираемых мусором. Сборщиком мусора подлежат объекты, а не переменные. Если переменная в области видимости ссылается на объект, она не может быть обработана сборщиком мусора. Проще говоря, сборщиком мусора может быть произведен сборщик мусора только тогда, когда на объект больше не ссылается какая-либо переменная.
Итак, у нас есть три экземпляра A, создаваемых в этом коде. Они начинаются с ссылки a1
и т. Д., Но поскольку ссылки на переменные меняются, я буду ссылаться на экземпляры объектов как A1, A2 и A3. Поскольку вы не показали определение метода go
, я предполагаю, что он предназначен для вызова easyMethod
.
Поскольку переменной a1 присвоено значение null, ничего не указывает на экземпляр A1, поэтому он может быть собран с помощью сборщика мусора.
Поскольку переменная a2 никогда не переназначается (присвоение в easyMethod
не влияет на исходную переменную), экземпляр A2 не может быть обработан сборщиком мусора.
Поскольку easyMethod
всегда возвращает null
и a3 назначается результат этого метода, ничего не указывает на экземпляр A3, поэтому он также может быть собран с помощью сборщика мусора.
Не могли бы вы объяснить мне, почему a2 и a3 не собираются в мусор ?
Потому что a2 и a3 не являются объектами. Это переменные. Переменные не собираются по той простой причине, что они не могут быть распределены.
Ваш вопрос довольно запутанный.
Сборщик мусора работает с объектами, а не с переменными. Поэтому, когда вы говорите, что a2 имеет право на сборку мусора, это ничего не значит. Вы должны сказать, что объект, на который указывает a2 в строке N, имеет право на сборку мусора в строке N + M.
В вашем примере создается только 3 объекта. Это первый экземпляр create A и последний экземпляр create A, которые имеют право на сборщик мусора.