Welcome to Our Website

Shallow vs. Deep Copy in Java (Polski)

w tym artykule z mojego darmowego kursu Java 8 omówię różnicę między głęboką i płytką kopią. Możesz pobrać slajdy i artykuł w formacie PDF tutaj.

Co To jest kopia?

na początek chciałbym podkreślić czym jest kopia w Javie. Po pierwsze, rozróżnijmy kopię odniesienia i kopię obiektu. Kopia odniesienia, jak sama nazwa wskazuje, tworzy kopię zmiennej odniesienia wskazującą na obiekt., Jeśli mamy obiekt Car, ze zmienną myCar wskazującą na niego i wykonamy kopię referencyjną, będziemy mieć teraz dwie zmienne myCar, ale nadal jeden obiekt.

przykład 1

Kopia obiektu tworzy kopię samego obiektu. Więc gdybyśmy ponownie skopiowali nasz obiekt car, utworzylibyśmy kopię samego obiektu, a także drugą zmienną referencyjną odwołującą się do tego skopiowanego obiektu.

przykład 2

Co To jest obiekt?,

zarówno Kopia głęboka, jak i płytka są typami kopii obiektów, ale czym tak naprawdę jest obiekt? Często, gdy mówimy o obiekcie, mówimy o nim jako o jednej jednostce, której nie da się dalej rozbić, jak skromne ziarno kawy. Jest to jednak uproszczone.

przykład 3

powiedz, że mamy obiekt Person. Nasz obiekt Person składa się w rzeczywistości z innych obiektów, jak widać w przykładzie 4. Nasza osoba zawiera obiekt nazwy i obiektu adresu., Nazwa z kolei zawiera obiekt FirstName i LastName; obiekt Address składa się z obiektu Street i City. Więc kiedy mówię o osobie w tym artykule, mówię o całej sieci obiektów.

przykład 4

Dlaczego więc chcemy skopiować ten obiekt Person? Kopia obiektu, zwykle nazywana klonem, jest tworzona, jeśli chcemy zmodyfikować lub przenieść obiekt, zachowując jednocześnie oryginalny obiekt. Istnieje wiele różnych sposobów kopiowania obiektu, o których możesz dowiedzieć się w innym artykule., W tym artykule będziemy używać konstruktora kopiującego do tworzenia naszych kopii.

Płytka Kopia

najpierw porozmawiajmy o płytkiej kopii. Płytka Kopia obiektu kopiuje obiekt „główny”, ale nie kopiuje obiektów wewnętrznych. „Wewnętrzne obiekty” są współdzielone między oryginalnym obiektem a jego kopią. Na przykład w naszym obiekcie Person tworzymy drugą osobę, ale oba obiekty mają tę samą nazwę i adres.

spójrzmy na przykład kodowania. W przykładzie 5 Mamy naszą klasę Person, która zawiera obiekt Name i Address., Konstruktor kopiujący pobiera obiekt originalPerson i kopiuje jego zmienne referencyjne.

przykład 5

problem z płytką kopią polega na tym, że oba obiekty nie są niezależne. Jeśli zmodyfikujesz obiekt nazwy jednej osoby, zmiana zostanie odzwierciedlona w obiekcie drugiej osoby.

zastosujmy to do przykładu. Powiedzmy, że mamy obiekt Person ze zmienną referencyjną mother; następnie robimy kopię matki, tworząc obiekt drugiej osoby, syn. Jeśli później w kodzie syn spróbuje przenieść () modyfikując swój obiekt adresowy, matka porusza się razem z nim!,

Person mother = new Person(new Name(…), new Address(…));Person son = new Person(mother);son.moveOut(new Street(…), new City(…));

przykład 6

dzieje się tak, ponieważ nasze obiekty matka i syn mają ten sam obiekt adresowy, co widać na przykładzie 7. Gdy zmieniamy adres w jednym obiekcie, zmienia się on w obu!

przykład 7

głęboka Kopia

w przeciwieństwie do płytkiej kopii, głęboka kopia jest w pełni niezależną kopią obiektu. Gdybyśmy skopiowali nasz obiekt Person, skopiowalibyśmy całą strukturę obiektu.,

przykład 8

zmiana obiektu adresu jednej osoby nie byłaby odzwierciedlona w drugim obiekcie, jak widać na schemacie w przykładzie 8. Jeśli spojrzymy na kod w przykładzie 9, widać, że nie tylko używamy konstruktora kopiującego na naszym obiekcie Person, ale również używamy konstruktorów kopiujących na obiektach wewnętrznych.

przykład 9

używając tej głębokiej kopii, możemy ponownie spróbować przykład matka-syn z przykładu 6. Teraz syn jest w stanie z powodzeniem wyprowadzić się!,

jednak to nie koniec historii. Aby stworzyć prawdziwą głęboką kopię, musimy kopiować wszystkie zagnieżdżone elementy obiektu Person, dopóki nie zostaną tylko prymitywne typy i „niezmienne”. Spójrzmy na klasę Street, aby lepiej to zilustrować:

przykład 10

obiekt Street składa się z dwóch zmiennych instancji – String name I int number. liczba int jest wartością pierwotną, a nie obiektem. Jest to po prostu prosta wartość, której nie można udostępnić, więc tworząc zmienną drugiej instancji, automatycznie tworzymy niezależną kopię., Ciąg jest niezmienny. Krótko mówiąc, niezmienny jest obiektem, który raz utworzony, nigdy nie może być zmieniony. Dlatego możesz go udostępnić bez konieczności tworzenia głębokiej kopii.

podsumowanie

na zakończenie chciałbym opowiedzieć o kilku technikach kodowania, których użyliśmy w naszym przykładzie matka-syn. Tylko dlatego, że głęboka Kopia pozwoli Ci zmienić wewnętrzne szczegóły obiektu, takie jak obiekt Address, nie oznacza to, że powinieneś., W ten sposób zmniejszyłoby to jakość kodu, ponieważ uczyniłoby klasę Person bardziej podatną na zmiany – za każdym razem, gdy Klasa Adresowa zostanie zmieniona, będziesz musiał (potencjalnie) zastosować zmiany również do klasy Person. Na przykład, jeśli Klasa adres nie zawiera już obiektu Street, musielibyśmy zmienić metodę moveOut () w klasie Person oprócz zmian, które już wprowadziliśmy do klasy adres.

w przykładzie 6 tego artykułu wybrałem tylko użycie nowego obiektu ulicy i miasta, aby lepiej zilustrować różnicę między płytką a głęboką kopią., Zamiast tego, zalecałbym przypisanie nowego obiektu adresowego, aby skutecznie przekształcić go w hybrydę płytkiej i głębokiej kopii, jak widać w przykładzie 10:

Person mother = new Person(new Name(…), new Address(…));Person son = new Person(mother);son.moveOut(new Address(...));

przykład 11

w terminach zorientowanych obiektowo narusza to hermetyzację i dlatego należy tego unikać. Enkapsulacja jest jednym z najważniejszych aspektów programowania obiektowego. W tym przypadku naruszyłem enkapsulację poprzez dostęp do wewnętrznych szczegółów obiektu adresu w naszej klasie osoby., To szkodzi naszemu kodowi, ponieważ teraz splątaliśmy klasę Person w klasie adresowej i jeśli wprowadzimy zmiany w klasie adresowej w dół linii, może to zaszkodzić klasie Person, jak wyjaśniłem powyżej. Podczas gdy oczywiście musisz połączyć różne klasy, aby mieć projekt kodowania, za każdym razem, gdy łączysz dwie klasy, musisz przeanalizować koszty i korzyści.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *