niedziela, grudnia 29, 2013

clone() i Cloneable się mszczą ;-)

W miarę znam Java'ę. Nie twierdzę, że perfect, ale nieźle.

Rozumiem jak działają refleksje i serializacja, rozumiem wait() i notify(), ale wychodzi na to, że nigdy nie rozumiałem clone() i Clonable ;-)

Okazuje się, że taki kod:


public class MyClass implements Cloneable {
private int x;
private String str;

public MyClass(int x, String str) { this.x = x; this.str = str; }

public int getX() { return x; }
public String getStr() { return str; }

public MyClass clone() {
try {
return (MyClass)super.clone();
} catch (CloneNotSupportedException cnse) {
throw new AssertionError();
}
}

public static void main(String[] args) {
MyClass c = new MyClass(1, "aga");
MyClass c2 = c.clone();
System.out.println(c2.str);
}
}

Wypisze "aga", bo Java zrobi płytką kopię obiektu.
Ja głupi jak musiałem kilka razy w życiu popełnić clone() to kopiowałem tam pola.

Jakoś ten rozdział mi umknął w Effective Java ;-)

Jak nie dodamy implementacji Clonable to nam taki kod wywali AssertionError bo w miejscu super.clone() poleci CloneNotSupportedException.

Jak rozumiem JVM w natywnym kodzie po prostu tworzy płytką kopię obiektu i wszystko działa jak powinno....
Niesie za sobą wiele niebezpieczeństw, bo kopiowanie odbywa się przez "wartość", w przypadku prymitywu jest to wartość rzeczywista, a w przypadku referencji skopiowana jest referencja.
Tutaj tak się dzieje ze String, ale na szczęście String jest niemutowalne i nie ma problemu.
Gdyby jednak zamiast String było List<String> to nasz nowy obiekt dostałby tą samą listę, którą zawierał w sobie obiekt klonowany. Wtedy to trzeba naprawić przez ręczne stworzenie nowej lisy i jej skopiowanie obiekt po obiekcie.... ale jak te kopiowane obiekty są mutowalne to też jest problem i też trzeba go przeskoczyć.

Dla mnie jednak wiadomością dnia jest fakt stworzenia płytkiej kopi obiektu :-) Nie wiedziałem, że to tak działa.
Wstyd mi,  ale nigdy nawet gdy przeglądałem kod JDK nie wpadłem na to, że ten idiom z super.clone() robi coś użytecznego....

Czyli dobrze, że ponownie czytam Effective Java, tym razem od deski do deski ;-)


Podobne postybeta
Go dla Java'owca ;-) odcinek 1 "klasy"
Referencje w Java'ie
Javozagadka ;-)
My - Niedouczeni ;-)
Sztuczki tropiciela błędów, part 4