В об'єктно-орієнтованому програмуванні копіювання об'єкта — це створення копії існуючого об'єкта, одиниці даних в об'єктно-орієнтованому програмуванні. Результуючий об'єкт називається копією об'єкта або просто копією. Копіювання є базовою операцією, але має тонкощі та може мати значні накладні витрати. Є кілька способів скопіювати об'єкт, найчастіше за допомогою конструктора копіювання або . Копіювання здебільшого виконується для того, щоб копію можна було змінити або перемістити, або зберегти поточне значення. Якщо жодна з цих дій непотрібна, то посилання на оригінальні дані є достатнім та більш ефективним, оскільки копіювання не відбувається.
Об'єкти зазвичай зберігають складені дані. У простих випадках копіювання можна виконати шляхом виділення нового неініціалізованого об'єкта та копіювання всіх полів (атрибутів) з оригінального об'єкта, у складніших випадках це не призводить до бажаної поведінки.
Способи копіювання
Мета проектування більшості об'єктів полягає в тому, щоб створити схожість із монолітним блоком (хоча при цьому більшість з них не є такими). Оскільки об'єкти складаються з кількох різних частин, копіювання стає нетривіальним. Існує кілька стратегій вирішення цієї проблеми.
Розглянемо об'єкт A, який містить поля xi (точніше, розглянемо, що A є рядком, а xi — масивом його символів). Існують різні стратегії створення копії A, які називаються поверхневою (простою) копією та глибокою копією. Багато мов програмування дозволяють загальне копіювання за допомогою тільки однієї або однієї з декількох стратегії, визначаючи або одну операцію копіювання, або окремі операції поверхневого копіювання та глибокого копіювання. Зауважте, що використання посилання на вже існуючий об'єкт A ще більш поверхнево, адже в цьому випадку взагалі немає ніякого нового об'єкта, а є лише нове посилання.
Термінологія поверхневої копії та глибокої копії відноситься до Smalltalk-80. Та ж сама відмінність має місце для порівняння об'єктів на предмет рівності: існує різниця між ідентичністю (той самий об'єкт) і рівністю (ті ж самі однакові значення), що відповідає поверхневій рівності та глибокій рівності (першого рівня) двох посилань на об'єкти. Але потім постає питання, чи означає рівність 1) порівняння лише полів відповідного об'єкта чи 2) розіменування деяких або всіх полів і порівняння їхніх значень по черзі (наприклад, чи є два зв'язані списки рівними, якщо вони мають однакові вузли чи однакові значення?).
Поверхнева (проста) копія
Одним із методів копіювання об'єкта є поверхневе копіювання. У цьому випадку створюється новий об'єкт B, а значення полів A копіюються в B. Це також відомо як копія по полях, або пополева копія. Якщо значення поля є посиланням на об'єкт (наприклад, адресу пам'яті), воно копіює посилання, отже посилаючись на той самий об'єкт, що й A, а якщо значення поля є примітивним типом, воно копіює значення примітивного типу. У мовах без примітивних типів (де все є об'єктом), усі поля копії B є посиланнями на ті самі об'єкти, що й поля оригінального A. Таким чином, об'єкти, на які посилаються, є спільними, тому якщо один із цих об'єктів змінено (A або B), зміни видно в іншому. Поверхневі копії прості та зазвичай дешеві, оскільки зазвичай їх можна реалізувати, просто точно копіюючи біти.
Глибока копія
Глибока копія означає, що поля розіменовуються: замість посилань на об'єкти, що копіюються, створюються нові об'єкти копії для будь-яких об'єктів, на які посилаються, а посилання на них розміщуються в B. Результат відрізняється від результату, який дає поверхнева копія тим, що об'єкти, на які посилається копія B, відрізняються від тих, на які посилається A, і незалежні. Глибокі копії дорожчі через необхідність створення додаткових об'єктів і можуть бути значно складнішими через посилання, які можуть утворювати складний граф.
Глибоке копіювання — це процес, у якому процес копіювання відбувається рекурсивно. Це означає спочатку створення нового об'єкта колекції, а потім рекурсивне заповнення його копіями дочірніх об'єктів, знайдених в оригіналі. У разі глибокого копіювання копія об'єкта копіюється в інший об'єкт. Це означає, що будь-які зміни, внесені до копії об'єкта, не відображаються на оригінальному об'єкті. У Python це реалізовано за допомогою функції «deep copy()».
Комбінація
У більш складних випадках деякі поля в копії повинні мати спільні значення з оригінальним об'єктом (як у поверхневій копії), що відповідає зв'язку «асоціації»; і деякі поля повинні мати копії (як у глибокій копії), що відповідає зв'язку «агрегація». У цих випадках зазвичай потрібна спеціальна реалізація копіювання; ця проблема та рішення датуються Smalltalk-80. Крім того, поля можна позначити як такі, що вимагають поверхневої або глибокої копії, а операції копіювання генерувати автоматично (аналогічно і операції порівняння). Однак це не реалізовано в більшості об'єктно-орієнтованих мов, хоча в Eiffel є часткова підтримка.
Реалізація
Майже всі об'єктно-орієнтовані мови програмування надають певний спосіб копіювання об'єктів. Оскільки більшість мов не забезпечують більшості об'єктів для програм, програміст повинен самостійно визначити, як саме об'єкт слід копіювати, а також визначити, чи є два об'єкти ідентичними або чи можна їх навіть порівнювати. Багато мов програмування забезпечують певну поведінку за замовчуванням.
Спосіб розв'язання копіювання залежить від конкретної мови, а також від концепція об'єкта в неї.
Лінива копія
Лінива копія — це специфічна реалізація глибокої копії. Під час початкового копіювання об'єкта використовується (швидка) поверхнева копія. При цьому також додатково використовується спеціальний лічильник для відстеження кількості об'єктів, які спільно використовують дані. Коли програма хоче змінити об'єкт, вона може визначати, чи є дані спільними (перевіривши лічильник), і за потреби може зробити глибоку копію.
Лінива копія виглядає зовні так само, як глибока копія, але використовує (за можливості) швидкість поверхневої копії. Недоліком є досить високі, але постійні базові накладні витрати через лічильник. Крім того, у певних ситуаціях можуть спричинити проблеми так звані .
Відкладене копіювання пов'язане з копіюванням при записуванні.
В Java
Далі наведено приклади для однієї з найпоширеніших об'єктно-орієнтованих мов — Java, які мають охоплювати майже всі способи вирішення цієї проблеми.
На відміну від C++, доступ до об'єктів у Java завжди здійснюється непрямо — опосередковано через посилання. Об'єкти ніколи не створюються неявно, натомість вони завжди передаються або призначаються змінною-посиланням.Віртуальна машина Java керує збиранням сміття, щоб об'єкти очищалися після того, як вони стали недоступними. У Java немає автоматичного способу копіювання будь-якого заданого об'єкта.
Копіювання зазвичай виконується методом clone() класу. Цей метод, у свою чергу, викликає метод clone() свого батьківського класу, щоб отримати копію, а потім виконує будь-які індивідуальні процедури копіювання. Зрештою це приводить до методу clone() найвищого класу Object — методу, який створює новий екземпляр того самого класу, що й об'єкт, а також копіює всі поля до нового екземпляра («поверхнева копія»). Якщо використовується цей метод копіювання, клас повинен реалізовувати інтерфейс Cloneable, інакше він викличе виключення CloneNotSupportedException. Після отримання копії від батьківського класу власний метод класу clone() може надати можливість спеціального клонування (наприклад, глибоке копіювання для дублювання деяких структур, на які посилається об'єкт) або надати новому екземпляру новий унікальний ідентифікатор.
Типом повернення clone() є Object, але реалізатори методу clone() натомість можуть записати тип об'єкта, який клонується, завдяки підтримці Java коваріантних типів повернення. Одна з переваг використання clone() полягає в тому, що, оскільки це метод, який можна заміщати (overridable method), ми можемо викликати clone() для будь-якого об'єкта, і він використовуватиме метод clone() свого класу.
Недоліком клонування є те, що часто неможливо отримати доступ до методу clone() абстрактного типу. Більшість інтерфейсів і абстрактних класів у Java не специфікують загальнодоступний метод clone(). Таким чином, часто єдиним способом використання методу clone() є відомий клас об'єкта, що суперечить принципу абстракції використання максимально узагальненого типу. Наприклад, якщо в Java є посилання на List, то не можна викликати clone() для цього посилання, оскільки List не специфікує загальнодоступний метод clone(). Реалізації List, наприклад, ArrayList або LinkedList, зазвичай мають методи clone(), але постійно обробляти тип класу об'єкта незручно і то є поганою абстракцією.
Ще один спосіб скопіювати об'єкти в Java — серіалізувати за допомогою інтерфейса Serializable. Це створює копії об'єктів, і, на відміну від клонування, така глибока копія, що витончено обробляє циклічні графи об'єктів, легко доступна з мінімальними зусиллями з боку програміста.
Обидва ці методи мають одну проблему: конструктор не використовується для об'єктів, що були скопійовані за допомогою клонування або серіалізації. Це може призвести до помилок із неправильно ініціалізованими даними, перешкоджає використанню final
полів члена, а також ускладнює обслуговування.
В інших мовах
У мові C# замість використання інтерфейсу ICloneable
можна використовувати узагальнений метод розширення для створення глибокої копії за допомогою відображення. Цей підхід має дві переваги. По-перше, це забезпечує гнучкість копіювання кожного об'єкта без необхідності специфікувати кожну властивість і змінну для копіювання вручну. По-друге, оскільки тип є узагальненим, компілятор гарантує, що цільовий об'єкт і оригінальний об'єкт мають однаковий тип.
У мові Objective-C спеціалізовані методи copy
та mutableCopy
успадковуються всіма об'єктами, при цьому mutableCopy
призначений для створення змінного типу оригінального об'єкта. Ці методи, у свою чергу, викликають методи copyWithZone
і mutableCopyWithZone
, відповідно, власне для виконання копіювання. Об'єкт має реалізувати відповідний метод copyWithZone
для того, щоб його можна було копіювати.
У мові Python модуль копіювання бібліотеки забезпечує поверхневе копіювання та глибоке копіювання об'єктів за допомогою функцій copy()
та deepcopy()
відповідно. Програміст може визначати спеціальні методи __copy__()
і __deepcopy__()
в об'єкті для того, щоб забезпечити свою власну реалізацію копіювання.
Див. також
Примітки
- Grogono та Sakkinen, 2000.
- Goldberg та Robson, 1983, с. 97—99.
- . Архів оригіналу за 10 лютого 2014. Процитовано 30 січня 2023.
- .NET Shallow vs Deep Copy Explanation.
- . Архів оригіналу за 4 березня 2016. Процитовано 10 квітня 2013.
- «Josh Bloch on Design: A Conversation with Effective Java Author, Josh Bloch», by Bill Venners, JavaWorld, January 4, 2002, p. 13
- Goldberg та Robson, 1983, с. 97.
- Python copy module
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
V ob yektno oriyentovanomu programuvanni kopiyuvannya ob yekta ce stvorennya kopiyi isnuyuchogo ob yekta odinici danih v ob yektno oriyentovanomu programuvanni Rezultuyuchij ob yekt nazivayetsya kopiyeyu ob yekta abo prosto kopiyeyu Kopiyuvannya ye bazovoyu operaciyeyu ale maye tonkoshi ta mozhe mati znachni nakladni vitrati Ye kilka sposobiv skopiyuvati ob yekt najchastishe za dopomogoyu konstruktora kopiyuvannya abo Kopiyuvannya zdebilshogo vikonuyetsya dlya togo shob kopiyu mozhna bulo zminiti abo peremistiti abo zberegti potochne znachennya Yaksho zhodna z cih dij nepotribna to posilannya na originalni dani ye dostatnim ta bilsh efektivnim oskilki kopiyuvannya ne vidbuvayetsya Ob yekti zazvichaj zberigayut skladeni dani U prostih vipadkah kopiyuvannya mozhna vikonati shlyahom vidilennya novogo neinicializovanogo ob yekta ta kopiyuvannya vsih poliv atributiv z originalnogo ob yekta u skladnishih vipadkah ce ne prizvodit do bazhanoyi povedinki Sposobi kopiyuvannyaMeta proektuvannya bilshosti ob yektiv polyagaye v tomu shob stvoriti shozhist iz monolitnim blokom hocha pri comu bilshist z nih ne ye takimi Oskilki ob yekti skladayutsya z kilkoh riznih chastin kopiyuvannya staye netrivialnim Isnuye kilka strategij virishennya ciyeyi problemi Rozglyanemo ob yekt A yakij mistit polya xi tochnishe rozglyanemo sho A ye ryadkom a xi masivom jogo simvoliv Isnuyut rizni strategiyi stvorennya kopiyi A yaki nazivayutsya poverhnevoyu prostoyu kopiyeyu ta glibokoyu kopiyeyu Bagato mov programuvannya dozvolyayut zagalne kopiyuvannya za dopomogoyu tilki odniyeyi abo odniyeyi z dekilkoh strategiyi viznachayuchi abo odnu operaciyu kopiyuvannya abo okremi operaciyi poverhnevogo kopiyuvannya ta glibokogo kopiyuvannya Zauvazhte sho vikoristannya posilannya na vzhe isnuyuchij ob yekt A she bilsh poverhnevo adzhe v comu vipadku vzagali nemaye niyakogo novogo ob yekta a ye lishe nove posilannya Terminologiya poverhnevoyi kopiyi ta glibokoyi kopiyi vidnositsya do Smalltalk 80 Ta zh sama vidminnist maye misce dlya porivnyannya ob yektiv na predmet rivnosti isnuye riznicya mizh identichnistyu toj samij ob yekt i rivnistyu ti zh sami odnakovi znachennya sho vidpovidaye poverhnevij rivnosti ta glibokij rivnosti pershogo rivnya dvoh posilan na ob yekti Ale potim postaye pitannya chi oznachaye rivnist 1 porivnyannya lishe poliv vidpovidnogo ob yekta chi 2 rozimenuvannya deyakih abo vsih poliv i porivnyannya yihnih znachen po cherzi napriklad chi ye dva zv yazani spiski rivnimi yaksho voni mayut odnakovi vuzli chi odnakovi znachennya Poverhneva prosta kopiya Odnim iz metodiv kopiyuvannya ob yekta ye poverhneve kopiyuvannya U comu vipadku stvoryuyetsya novij ob yekt B a znachennya poliv A kopiyuyutsya v B Ce takozh vidomo yak kopiya po polyah abo popoleva kopiya Yaksho znachennya polya ye posilannyam na ob yekt napriklad adresu pam yati vono kopiyuye posilannya otzhe posilayuchis na toj samij ob yekt sho j A a yaksho znachennya polya ye primitivnim tipom vono kopiyuye znachennya primitivnogo tipu U movah bez primitivnih tipiv de vse ye ob yektom usi polya kopiyi B ye posilannyami na ti sami ob yekti sho j polya originalnogo A Takim chinom ob yekti na yaki posilayutsya ye spilnimi tomu yaksho odin iz cih ob yektiv zmineno A abo B zmini vidno v inshomu Poverhnevi kopiyi prosti ta zazvichaj deshevi oskilki zazvichaj yih mozhna realizuvati prosto tochno kopiyuyuchi biti Gliboka kopiya Gliboka kopiya v procesi Gliboka kopiya v rezultati Gliboka kopiya oznachaye sho polya rozimenovuyutsya zamist posilan na ob yekti sho kopiyuyutsya stvoryuyutsya novi ob yekti kopiyi dlya bud yakih ob yektiv na yaki posilayutsya a posilannya na nih rozmishuyutsya v B Rezultat vidriznyayetsya vid rezultatu yakij daye poverhneva kopiya tim sho ob yekti na yaki posilayetsya kopiya B vidriznyayutsya vid tih na yaki posilayetsya A i nezalezhni Gliboki kopiyi dorozhchi cherez neobhidnist stvorennya dodatkovih ob yektiv i mozhut buti znachno skladnishimi cherez posilannya yaki mozhut utvoryuvati skladnij graf Gliboke kopiyuvannya ce proces u yakomu proces kopiyuvannya vidbuvayetsya rekursivno Ce oznachaye spochatku stvorennya novogo ob yekta kolekciyi a potim rekursivne zapovnennya jogo kopiyami dochirnih ob yektiv znajdenih v originali U razi glibokogo kopiyuvannya kopiya ob yekta kopiyuyetsya v inshij ob yekt Ce oznachaye sho bud yaki zmini vneseni do kopiyi ob yekta ne vidobrazhayutsya na originalnomu ob yekti U Python ce realizovano za dopomogoyu funkciyi deep copy Kombinaciya U bilsh skladnih vipadkah deyaki polya v kopiyi povinni mati spilni znachennya z originalnim ob yektom yak u poverhnevij kopiyi sho vidpovidaye zv yazku asociaciyi i deyaki polya povinni mati kopiyi yak u glibokij kopiyi sho vidpovidaye zv yazku agregaciya U cih vipadkah zazvichaj potribna specialna realizaciya kopiyuvannya cya problema ta rishennya datuyutsya Smalltalk 80 Krim togo polya mozhna poznachiti yak taki sho vimagayut poverhnevoyi abo glibokoyi kopiyi a operaciyi kopiyuvannya generuvati avtomatichno analogichno i operaciyi porivnyannya Odnak ce ne realizovano v bilshosti ob yektno oriyentovanih mov hocha v Eiffel ye chastkova pidtrimka RealizaciyaMajzhe vsi ob yektno oriyentovani movi programuvannya nadayut pevnij sposib kopiyuvannya ob yektiv Oskilki bilshist mov ne zabezpechuyut bilshosti ob yektiv dlya program programist povinen samostijno viznachiti yak same ob yekt slid kopiyuvati a takozh viznachiti chi ye dva ob yekti identichnimi abo chi mozhna yih navit porivnyuvati Bagato mov programuvannya zabezpechuyut pevnu povedinku za zamovchuvannyam Sposib rozv yazannya kopiyuvannya zalezhit vid konkretnoyi movi a takozh vid koncepciya ob yekta v neyi Liniva kopiya Liniva kopiya ce specifichna realizaciya glibokoyi kopiyi Pid chas pochatkovogo kopiyuvannya ob yekta vikoristovuyetsya shvidka poverhneva kopiya Pri comu takozh dodatkovo vikoristovuyetsya specialnij lichilnik dlya vidstezhennya kilkosti ob yektiv yaki spilno vikoristovuyut dani Koli programa hoche zminiti ob yekt vona mozhe viznachati chi ye dani spilnimi perevirivshi lichilnik i za potrebi mozhe zrobiti gliboku kopiyu Liniva kopiya viglyadaye zovni tak samo yak gliboka kopiya ale vikoristovuye za mozhlivosti shvidkist poverhnevoyi kopiyi Nedolikom ye dosit visoki ale postijni bazovi nakladni vitrati cherez lichilnik Krim togo u pevnih situaciyah mozhut sprichiniti problemi tak zvani Vidkladene kopiyuvannya pov yazane z kopiyuvannyam pri zapisuvanni V Java Dali navedeno prikladi dlya odniyeyi z najposhirenishih ob yektno oriyentovanih mov Java yaki mayut ohoplyuvati majzhe vsi sposobi virishennya ciyeyi problemi Na vidminu vid C dostup do ob yektiv u Java zavzhdi zdijsnyuyetsya nepryamo oposeredkovano cherez posilannya Ob yekti nikoli ne stvoryuyutsya neyavno natomist voni zavzhdi peredayutsya abo priznachayutsya zminnoyu posilannyam Virtualna mashina Java keruye zbirannyam smittya shob ob yekti ochishalisya pislya togo yak voni stali nedostupnimi U Java nemaye avtomatichnogo sposobu kopiyuvannya bud yakogo zadanogo ob yekta Kopiyuvannya zazvichaj vikonuyetsya metodom clone klasu Cej metod u svoyu chergu viklikaye metod clone svogo batkivskogo klasu shob otrimati kopiyu a potim vikonuye bud yaki individualni proceduri kopiyuvannya Zreshtoyu ce privodit do metodu clone najvishogo klasu Object metodu yakij stvoryuye novij ekzemplyar togo samogo klasu sho j ob yekt a takozh kopiyuye vsi polya do novogo ekzemplyara poverhneva kopiya Yaksho vikoristovuyetsya cej metod kopiyuvannya klas povinen realizovuvati interfejs Cloneable inakshe vin vikliche viklyuchennya CloneNotSupportedException Pislya otrimannya kopiyi vid batkivskogo klasu vlasnij metod klasu clone mozhe nadati mozhlivist specialnogo klonuvannya napriklad gliboke kopiyuvannya dlya dublyuvannya deyakih struktur na yaki posilayetsya ob yekt abo nadati novomu ekzemplyaru novij unikalnij identifikator Tipom povernennya clone ye Object ale realizatori metodu clone natomist mozhut zapisati tip ob yekta yakij klonuyetsya zavdyaki pidtrimci Java kovariantnih tipiv povernennya Odna z perevag vikoristannya clone polyagaye v tomu sho oskilki ce metod yakij mozhna zamishati overridable method mi mozhemo viklikati clone dlya bud yakogo ob yekta i vin vikoristovuvatime metod clone svogo klasu Nedolikom klonuvannya ye te sho chasto nemozhlivo otrimati dostup do metodu clone abstraktnogo tipu Bilshist interfejsiv i abstraktnih klasiv u Java ne specifikuyut zagalnodostupnij metod clone Takim chinom chasto yedinim sposobom vikoristannya metodu clone ye vidomij klas ob yekta sho superechit principu abstrakciyi vikoristannya maksimalno uzagalnenogo tipu Napriklad yaksho v Java ye posilannya na List to ne mozhna viklikati clone dlya cogo posilannya oskilki List ne specifikuye zagalnodostupnij metod clone Realizaciyi List napriklad ArrayList abo LinkedList zazvichaj mayut metodi clone ale postijno obroblyati tip klasu ob yekta nezruchno i to ye poganoyu abstrakciyeyu She odin sposib skopiyuvati ob yekti v Java serializuvati za dopomogoyu interfejsa Serializable Ce stvoryuye kopiyi ob yektiv i na vidminu vid klonuvannya taka gliboka kopiya sho vitoncheno obroblyaye ciklichni grafi ob yektiv legko dostupna z minimalnimi zusillyami z boku programista Obidva ci metodi mayut odnu problemu konstruktor ne vikoristovuyetsya dlya ob yektiv sho buli skopijovani za dopomogoyu klonuvannya abo serializaciyi Ce mozhe prizvesti do pomilok iz nepravilno inicializovanimi danimi pereshkodzhaye vikoristannyu final poliv chlena a takozh uskladnyuye obslugovuvannya V inshih movah U movi C zamist vikoristannya interfejsu ICloneable mozhna vikoristovuvati uzagalnenij metod rozshirennya dlya stvorennya glibokoyi kopiyi za dopomogoyu vidobrazhennya Cej pidhid maye dvi perevagi Po pershe ce zabezpechuye gnuchkist kopiyuvannya kozhnogo ob yekta bez neobhidnosti specifikuvati kozhnu vlastivist i zminnu dlya kopiyuvannya vruchnu Po druge oskilki tip ye uzagalnenim kompilyator garantuye sho cilovij ob yekt i originalnij ob yekt mayut odnakovij tip U movi Objective C specializovani metodi copy ta mutableCopy uspadkovuyutsya vsima ob yektami pri comu mutableCopy priznachenij dlya stvorennya zminnogo tipu originalnogo ob yekta Ci metodi u svoyu chergu viklikayut metodi copyWithZone i mutableCopyWithZone vidpovidno vlasne dlya vikonannya kopiyuvannya Ob yekt maye realizuvati vidpovidnij metod copyWithZone dlya togo shob jogo mozhna bulo kopiyuvati U movi Python modul kopiyuvannya biblioteki zabezpechuye poverhneve kopiyuvannya ta gliboke kopiyuvannya ob yektiv za dopomogoyu funkcij copy ta deepcopy vidpovidno Programist mozhe viznachati specialni metodi copy i deepcopy v ob yekti dlya togo shob zabezpechiti svoyu vlasnu realizaciyu kopiyuvannya Div takozhKonstruktor kopiyuvannya Perevantazhennya operatoriv Pidrahunok posilan Kopiyuvannya pri zapisuvanniPrimitkiGrogono ta Sakkinen 2000 Goldberg ta Robson 1983 s 97 99 Arhiv originalu za 10 lyutogo 2014 Procitovano 30 sichnya 2023 NET Shallow vs Deep Copy Explanation Arhiv originalu za 4 bereznya 2016 Procitovano 10 kvitnya 2013 Josh Bloch on Design A Conversation with Effective Java Author Josh Bloch by Bill Venners JavaWorld January 4 2002 p 13 Goldberg ta Robson 1983 s 97 Python copy module