Мелкие, глубокие и защитные копии
Мелкие и глубокие копии — это очень простые определения, используемые в таких языках программирования, как 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.