Глубокая и мелкая копия 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
эти два массива действительно мелкие копии друг друга. То есть у вас была копия ссылок на StringBuilder
s. Упомянутые объекты одинаковы.
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
никогда не менялся никак.