Мелкие, глубокие и защитные копии

Мелкие и глубокие копии — это очень простые определения, используемые в таких языках программирования, как C и C++. Это может немного сбить с толку, если ваш основной язык программирования — Java. В этом посте я собираюсь рассмотреть эти определения с точки зрения подхода к языку программирования Java.

Рассмотрим следующий код script:

User userA = new User();
userA.setName("Paco");
userA.setLastName("Perez");
User userB = userA;
userB.setName("Juan");
assertEquals(userA, userB);

Почему этот assertEquals не дает сбоев?

В Java после создания экземпляра переменной (userA = new User()) виртуальная машина создает ссылку в памяти, и эта ссылка прикрепляется к недавно созданному экземпляру. Когда вызывается «User userB = userA», создается переменная userB со всей той же информацией об экземпляре userA, включая эту ссылку в памяти. Таким образом, любое обновление в userB будет постоянным в userA, так как оба экземпляра практически одинаковы.

Так что же такое поверхностное копирование?

Приведенный выше пример является определением поверхностного копирования. Это метод копирования всех атрибутов из одного экземпляра в другой, когда оба экземпляра указывают на одну и ту же позицию в памяти. По умолчанию в Java на все ссылаются, поэтому каждый раз, когда вы видите в коде «=», вы реализуете поверхностное копирование.

Внутреннее использование Shallow выполняется быстрее, поскольку обновляются только ссылки. Кроме того, это экономит место в памяти, поскольку для создания новых экземпляров больше не требуется места. Когда экземпляр собирается GC, все экземпляры, на которые он ссылается, также собираются.

Так что же такое глубокая копия?

Как и в случае с Shallow, это также метод копирования атрибутов из одного экземпляра в другой с той разницей, что он создает экземпляр с новой ссылкой в ​​нем, а затем копирует каждый из атрибутов. Это продублирует пространство в памяти. Вот код, который его представляет:

User userA = new User();
userA.setName("Paco");
userA.setLastName("Perez");
User userB = User();
userB.setName(userA.getName());
userB.setLastName(userA.getLastName());
assertEquals(userA.getName(), userB.getName());
assertEquals(userA.getLastName(), userB.getLastName());
assertNotEquals(userA, userB);

Существует также короткая версия этого кода, реализующая метод clone. При правильной реализации клон вернет новый экземпляр пользователя со всеми выбранными вами атрибутами, скопированными из пользователя А в пользователя Б.

User userA = new User()
userA.setName("Paco");
userA.setLastName("Perez");
User userB = userA.clone();
assertEquals(userA.getName(), userB.getName());
assertEquals(userA.getLastName(), userB.getLastName());
assertNotEquals(userA, userB);

Хотя такие копии занимают больше места и требуют больше времени для внутреннего запуска, они обычно используются в проектах, которым требуется быстро обновлять/генерировать вызовы API или копии скриптов баз данных на основе информации о текущих данных.

Так что же такое защитная копия?

Наконец, основываясь на обоих вышеприведенных определениях, рассмотрите следующий код как в Shallow Copy:

final User userA = new User("Paco", "Perez");
User userB = userA;
userB.setName("Juan");

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

Таким образом, используя Deep Copy, у вас будет новый экземпляр, который вы можете обновлять или манипулировать им по своему усмотрению, поскольку userB не является окончательным.

final User userA = new User("Paco", "Perez");
User userB = userA.clone();
userB.setName("Juan");

Защитные копии в основном используются в параллельном программировании, поскольку у каждого потока есть собственная копия всех переменных ресурсов, необходимых для правильной работы.

Чтобы узнать больше

Это отличный старт для Стратегий оценки, которые включают передачу по ссылке и по значению.

Есть несколько примеров кода на Java, которые дополняют идею этого поста: Передается ли Java по ссылке или по значению? Тони Синтес

Это Документация Oracle с большим количеством примеров. Особенно те, которые включают примитивы, объекты и списки.

Наконец, лучшее объяснение Защитных копий можно найти в Effective Java book by Joshua Bloch.