Подходящие переменные для сборки мусора в Java

Я готовлюсь к OCPJP и застрял на следующем контрольном вопросе:

Дано:

3. interface Animal { void makeNoise(); }

4. class Horse implements Animal {
5.     Long weight = 1200L;
6.     public void makeNoise() { System.out.println("whinny"); }
7. }

8. public class Icelandic extends Horse {
9.     public void makeNoise() { System.out.println("vinny"); }

10.    public static void main(String[] args) {
11.        Icelandic i1 = new Icelandic();
12.        Icelandic i2 = new Icelandic();
12.        Icelandic i3 = new Icelandic();
13.        i3 = i1; i1 = i2; i2 = null; i3 = i1;
14.    }
15. }

Когда достигается строка 14, сколько объектов подходит для сборщика мусора?

A. 0

B. 1

C. 2

D. 3

E. 4

F. 6

Их правильный ответ — E, то есть четыре объекта, но я не знаю почему. С моей точки зрения, i2 и его вес получат право на сборку мусора. Возможно я что-то упускаю, подскажите.


person user998692    schedule 29.11.2012    source источник
comment
Их вопрос немного глуп, так как сборка мусора не имеет значения при завершении программы (в строке 14)...   -  person DNA    schedule 30.11.2012
comment
Просто уточнение - вы уверены, что weight - это Long, а не long (объект, а не примитив)?   -  person DNA    schedule 30.11.2012
comment
Подождите... разве это не полностью зависит от того, как называется эта программа? Строки являются объектами, поэтому любые предоставленные аргументы изменят количество объектов.   -  person Mike G    schedule 30.11.2012
comment
Эти String находятся в пуле строковых констант, поэтому они не подходят для сборки мусора (по крайней мере, в смысле вопроса).   -  person user802421    schedule 30.11.2012
comment
Да, я уверен, что вес Лонг, я сделал копипаст для всего кода.   -  person user998692    schedule 30.11.2012


Ответы (3)


Давайте назовем Icelandic() в строке 11 IceA, в строке 12 IceB и так далее.

После создания

i1 = IceA
i2 = IceB
i3 = IceC

После i3 = i1

i1 = IceA
i2 = IceB
i3 = IceA

После i1 = i2

i1 = IceB
i2 = IceB
i3 = IceA

После i2 = null

i1 = IceB
i2 = null
i3 = IceA

После i3 = i1

i1 = IceB
i2 = null
i3 = IceB

Таким образом, остается только Icelandic(), созданный в строке 12. Теперь у каждого Icelandic() есть Long weight, поэтому IceA и IceC теперь не имеют ссылок, что означает, что 4 объекта (IceA, IceA.weight, IceC, IceC.weight) доступны для GC.


Другие вопросы:

  1. args по-прежнему args, выход за рамки в этом вопросе не считается
  2. Long weight не объявляется статически, поэтому каждый экземпляр класса имеет объект weight.
person durron597    schedule 29.11.2012
comment
А как же вес(а)? - person DNA; 30.11.2012
comment
Но в строке 14 все i1, i2 и i3 выходят за рамки, так что IceB тоже можно GC'ировать, верно? - person DNA; 30.11.2012
comment
@DNA: Это был мой первоначальный ответ, но тогда ответ был бы 6. Очевидно, что задающий вопрос хочет знать, что доступно для gc, ДО ТОГО, как что-то выйдет за рамки. - person durron597; 30.11.2012
comment
Ох уж эти плохо сформулированные экзаменационные вопросы ;-) - person DNA; 30.11.2012

Назовем первый созданный исландский объект «A», второй — «B», а третий — «C». После строки 12 на них ссылаются i1, i2 и i3 соответственно.

Теперь делаем:

i3 = i1; // object "C" is no longer referenced, object "A" is now referenced by i1 and i3
i1 = i2; // object "A" is just referenced by i3, object "B" is referenced by i1 and i2
i2 = null; // object "B" is just referenced by i1 now
i3 = i1; // object "B" is referenced by i1 and i3, object "A" is no longer referenced

Таким образом, на объекты «A» и «C» больше не ссылаются, и они вместе со своим «весом» подходят для сборки мусора, так что всего четыре объекта.

person GriffeyDog    schedule 29.11.2012
comment
Но все эти ссылки выходят за рамки и, следовательно, не препятствуют сборке мусора любого из этих объектов. - person DNA; 30.11.2012
comment
@DNA, я понимаю, что когда достигается строка 14, это означает незадолго до выхода из main(). Судя по всему, именно это и имели в виду авторы вопроса, если ответ равен 4. - person GriffeyDog; 30.11.2012
comment
@DNA: я согласен с вами, но я думаю, что автор вопроса говорит ДО строки 14, а не после того, как переменные выходят за рамки - person durron597; 30.11.2012
comment
Ах, это бы объяснило - это полностью меняет смысл вопроса и делает все возни в строке 13 актуальными (иначе это довольно жестокая диверсия в экзаменационном вопросе!) - person DNA; 30.11.2012
comment
Да, автору вопроса было бы лучше вставить реальную строку кода (например, System.out.println() или что-то подобное) в строку 14 вместо закрывающей скобки. - person GriffeyDog; 30.11.2012

У вас будет 4 объекта в системе, 3 экземпляра Icelandic и 1 экземпляр Long.

Когда вы присваиваете константный объект какой-либо переменной, компилятор использует тип объекта private static final Long long1200 = Long.valueOf(1200L);, который используется всеми экземплярами weight.

Обертки примитивного типа неизменяемы, поэтому выполнять эту оптимизацию безопасно.

РЕДАКТИРОВАТЬ: возможно, я ошибаюсь, потому что это сработает, если мы несколько раз будем ссылаться на одну и ту же константу, что не так.

person hoaz    schedule 29.11.2012
comment
Вы частично правы: компилятор или реализация Long оптимизирует экземпляры для меньших чисел, так что это только один. Больше не нужно больше: ideone.com/nsQoHr. - person zapl; 30.11.2012
comment
Конечно, это оптимизация Long.valueOf() во время выполнения, я думал, что компилятор также выполняет постоянную оптимизацию, и это оказалось неправильным. - person hoaz; 30.11.2012