Effective Java Item 11 note
Override clone judiciously
Published in
4 min readMay 29, 2018
看起來如果要override clone的話,大原則是如果要複製,那麼就要保證你要複製的class可以給出一個不是共用的內部field,以及該內部field也是一樣的原則。以避免變成都在改同一個物件但你不知道。然後要保證複製出來的object其內容是一樣的。
大致上非必要是不推薦使用clone的,下面會提到取代clone這種比較文件規範式的作法。
如果要使一個物件可以被複製,
- 需要implements Cloneable(這個interface裡面沒有任何method,所以才說是文件式的規範)
- 把protected Object clone() 改成(這也是自己要做的,從1.5開始有covariant return type,就是override method的return type可以是return subclass)
@Override
public YourObject clone() throws CloneNotSupportedException {
//如果要複製的對象其內容物全部都是primitive,可以只這樣做就好,可以幫client少做的事就自己做掉。
return (YourObject)super.clone();
//如果要複製的對象其內容物裡面有可變的object,就要自己去處理該物件的clone
YourObject o = (YourObject) super.clone();
o.someobjects = someobjects.clone();
return o;
//但上面這個情況如果someobjects是final的時候就麻煩了,除非someobjects是可以安全共享的,不然就要把final拿掉了。
//如果要複製的對象其內容裡面有可變的array object,就要去處理每個object的clone。
}
在Java裡面的規範是:
- x.clone() != x 是true
- x.clone().getClass() == x.getClass() 是true
- x.clone().equals(x) 是true
- 然後不使用constructor去建造出來
但都不是絕對的要求,只是希望而已。(所以沒辦法強迫接受它,只能自己注意它,所以不推薦使用)
然後底下是使用clone的一些建議,
- 跟constructor一樣,不要在建構的過程中,使用到新object裡面任何非final的method(item 17),避免call到override的method,導致兩個object的內容可能會不一樣
- 如果是繼承考量的class去override了clone,那麼就要跟Object.clone的行為是一樣。給要繼承的人可以有彈性。如果是implements了cloneable的class,那就要有個override public clone()
- 小心thread上面使用clone(),需要很好的sync
結論就是,除非你已經不得已要extends一個implements Cloneable的class,那你就只能去override clone,避免人家在extends你的class的時候有問題(文件規範的壞處)。
然後可以用底下兩個取代clone,如果可以的話,而且有很多好處,例如:不是文件規範的條件,不會與final field有衝突,不會丟出checked exception,不需要轉型。
Copy constructor
public YourObject(YourObject o)Copy factory
public static YourObject newInstance(YourObject o)
P.S. 底下這個blog也有解釋到如果中間有個class沒有override好clone會發生什麼事。