Глубокая и мелкая копия Java

Я готовлюсь к экзамену по Java, и то, что я узнал, практически отличается от того, что преподается в теории.

Ниже приведен код:

    StringBuilder num3[]= new StringBuilder[2];
    num3[0]= new StringBuilder("Pine");
    num3[1]= new StringBuilder("Oak");
    StringBuilder num4[] = new StringBuilder[2];
    System.arraycopy(num3, 0, num4, 0, 2);
    System.out.println(num3[0]==num4[0]);
    System.out.println(num4[0]);
    num3[0] = new StringBuilder("Choc"); 
    System.out.println(num3[0]);
    System.out.println(num4[0]);

Выход:

правда
сосна
Шоколадка
сосна

Утверждение true указывает, что это мелкая копия, поскольку num4[0] ссылается на тот же объект num3[0]. Но когда я изменил num3 [0], я ожидал, что num4[0] тоже изменится.

Почему это происходит, если это мелкая копия?

Это потому, что новый объект создается для num3 [0], а на старый объект "Pine" StringBuilder ссылается массив num4?

Если да, может ли кто-нибудь дать мне пример для System.arraycopy, где эта мелкая копия очевидна?

Заранее спасибо, Кристиан

5 ответов

Решение

После System.arraycopyэти два массива действительно мелкие копии друг друга. То есть у вас была копия ссылок на StringBuilders. Упомянутые объекты одинаковы.

num3:  [ refA, refB ]                        num4: [ refA, refB ]
           |    |                                      |     |
           |    `-------> StringBuilder("Oak") <-------+-----' 
           `------------> StringBuilder("Pine") <------'

Но тогда вы измените ссылку в num3[0] указать на новый StringBuilder:

num3:  [ refC, refB ]                        num4: [ refA, refB ]
           |    |                                      |     |
           |    `-------> StringBuilder("Oak") <-------+-----' 
           |              StringBuilder("Pine") <------'
           `------------> StringBuilder("Choc")

Базовые объекты не изменились. Все, что вы сделали, изменили то, что ссылается на них.


System.arraycopy это как иметь for цикл, который копирует значения в массивах, за исключением того, что он намного более эффективен для больших массивов (так как современные процессоры имеют специальные инструкции для массового копирования памяти). Вам никогда не нужно это семантически; это просто оптимизация производительности.

num3[0] а также num4[0] являются ссылками на один и тот же объект, поэтому при изменении num3[0] это просто меняет где num3[0] указывает и не изменится где num4[0] указывает.

System.out.println(num3[0]==num4[0]);

Это возвращает true, потому что оба указывают на один и тот же объект, но оба являются индивидуальными.

Если бы вы сделали что-то вроде

num3[0].append("something") и тогда вы бы напечатали num3[0] а также num4[0] тогда оба были бы затронуты.

Вы не меняете num3[0], вы указываете на что-то другое, а именно на новый объект StringBuilder. num3[0] и num4[0] больше не указывают на один и тот же объект, поэтому num4[0] не меняется. Значения ссылок массива копируются, но если вы измените эти значения, это не повлияет на другой массив. На что это повлияет, если вы измените объекты, на которые они указывают, а не ссылки на эти объекты.

Думать о num3[0] а также num4[0] как два парня, указывающие на рюкзак. Если вы добавите вещи в рюкзак, они оба укажут на то, что было изменено. Тем не менее, если вы спросите num3[0] чтобы указать на телевизор, num4[0] по-прежнему будет указывать на рюкзак.

Это потому, что новый объект создается для num3[0], а на старый объект "Pine" StringBuilder ссылается массив num4?

Именно так.

Если да, может ли кто-нибудь дать мне пример для System.arraycopy, где эта мелкая копия очевидна?

Я не уверен, что понимаю этот вопрос. Никакая копия, будь то мелкая или глубокая, не может повлиять на то, что вы делаете после копирования.

Но попробуйте следующее:

num3[1].append("tree");
println(num4[1]);        // should be "Oaktree"

Мелкая копия в этом случае - не что иное, как новая ссылка на объект. У вас есть объект Pine с одним указателем на него хранится в Int num3, Теперь вы делаете мелкую копию (вы создаете новую ссылку), которая хранится в num4, Теперь у вас есть один Pine объект с двумя ссылками. Когда вы назначаете Choc в num3 количество ссылок уменьшается на 1, и вы фактически заменили ссылку на num3 с другим. Pine никогда не менялся никак.

Другие вопросы по тегам