Java: установка ссылки на ноль не повлияет на объект - PullRequest
5 голосов
/ 28 ноября 2011

У меня простой вопрос. В этом коде ниже, почему значение s3 все еще печатается, хотя раньше я устанавливал его в null. Кажется, сборщик мусора не будет вызван.

public class Test {
    public static void main(String[] args) {
         String s1 = "abc", s2 = "def", s3 = "ghj";

         String sarr[] = {s1, s2, s3};
         s3 = null;

         System.gc(); 

         for(int i = 0; i < sarr.length; i++) {
             System.out.print(sarr[i] + " "); //prints abc def ghj
         }
    }
 }

Любые мысли приветствуются.

Ответы [ 6 ]

11 голосов
/ 28 ноября 2011

Когда вы пишете:

// Moved [] to make it more idiomatic
String[] sarr = {s1, s2, s3};

То, что копирует значения s1, s2 и s3 (которые являются ссылками, не объектов) в массив. После выполнения инструкции переменные полностью не зависят от массива. Изменение значения любой из переменных s1, s2, s3 для ссылки на другую строку вообще не влияет на содержимое массива.

Это точно так же, как с другими заданиями, например,

string x = "hello";
string y = x;
x = null; // Doesn't affect y

и аргументы метода тоже.

Обратите внимание, что часть сбора мусора здесь - красная сельдь - хотя очевидно, что понимание этого важно для понимания сбора мусора, обратное неверно. Важно понимать, что:

  • Значения s1, s2 и s3 и элементы массива являются ссылками , а не объектами.
  • Значения копируются при создании массива, поэтому последующее изменение переменной не имеет значения

Теперь, чтобы продолжить пример, рассмотрим:

StringBuilder sb = new StringBuilder("Hello");
StringBuilder[] array = { sb };

sb.append(" world");
System.out.println(array[0]);

Это напечатает «Hello world», потому что здесь у нас есть только один StringBuilder объект , к которому относятся и sb и array[0]. При изменении данных внутри этот объект (что не то же самое, что изменение sb для ссылки на другой объект) делает изменение видимым, как бы вы к нему ни подходили. Это похоже на то, как я передаю адрес моего дома двум людям - если один из них раскрасит мой дом в красный цвет, другой тоже это увидит.

9 голосов
/ 28 ноября 2011

Вы переназначили s3, чтобы указать на что-то еще (ноль), но ссылка внутри массива по-прежнему указывает на исходное значение ("ghj").

s3 не является постоянным указателем на расположение массива. Значение s3 ( ссылка на строковое значение "ghj") было скопировано в массив. Сама переменная не связана и может свободно ссылаться на другой объект String независимо от того, что вы делаете с содержимым массива.

4 голосов
/ 28 ноября 2011

Поймите, что вы не можете заставить сборщик мусора работать; Вы можете только предположить, что он работает.

Чтобы ответить на ваш вопрос, вам нужно запомнить разницу между ссылкой и значением. Когда вы создаете экземпляр s3, вы указываете на «ghj». Когда вы создаете экземпляр sarr [2], вы также указываете на «ghj». Затем вы обнуляете ссылку s3, но sarr [2] по-прежнему указывает на строку «ghj» в куче.

1 голос
/ 28 ноября 2011

Java String является неизменным.Как только вы сделали это, это не изменится.Что вы сделали, это создали строку (неявно, через литерал "ghj" в вашем коде) и присвоили ссылку этой строке переменной s3.

После этогоВы помещаете свои три переменные в массив.В основном это происходит из-за того, что трем ссылкам дается место в массиве.

Затем вы устанавливаете переменную s3, указывающую на ноль. ссылка , которая была сохранена в s3, удаляется из нее и заменяется нулевым указателем.Но эта ссылка все еще находится в массиве.Ссылка на строку была скопирована в массив, а не на фактическую строку или саму переменную.

Поэтому, когда вы распечатываете содержимое массива, ссылка на вашу строку "ghj" все еще там ибудет использоваться.Поскольку эта ссылка также все еще активно доступна, она не будет собирать мусор.

Также учтите, что вызов System.gc() является признаком того, что вы хотите, чтобы сборщик мусора работал.Вы совсем не гарантированы, что это произойдет, когда метод вернется или в течение какого-либо временного ограничения, в этом отношении.

1 голос
/ 28 ноября 2011

Я предполагаю, что строка "ghj" добавлена ​​в пул строк.Когда вы устанавливаете s3 = null, переменная s3 больше не ссылается на ghj в пуле строк, но ваш элемент массива sarr [2] делает, следовательно, причина, по которой он все еще печатается правильно.

0 голосов
/ 28 ноября 2011

Поскольку значение s3 все еще упоминается из массива.

Что также стоит отметить, это то, что никогда не гарантируется, что System.gc() действительно вызовет сборщик мусора. Это всего лишь предложение для JVM.

...