Effective Java之谨慎地覆盖clone(十一)
Clone提供一種語言之外的機制:無需調用構造器就可以創建對象。
它的通用約定非常弱:
創建和返回該對象的一個拷貝。這個拷貝的精確含義取決于該對象的類。一般含義是,對于任何對象x,表達式x.clone() != x 將會是true,并且,表達式x.clone().getClass() == x.getClass() 將會是true,但這些不是絕對的要求,通常情況下,表達式 x.clone().equals(x) 將會是true,這也不是一個絕對的要求,拷貝對象往往是創建它的類的一個新實例,但它同時也會要求拷貝內部的數據結構。
如果類的每個域包含一個基本類型的值,或者包含一個指向不可變對象的引用,那么被返回的對象則正是所需要的對象,如
public class PhoneNumber implements Cloneable{private final int areaCode;private final int prefix;private final int lineNumber;public PhoneNumber(int areaCode, int prefix, int lineNumber) {rangeCheck(areaCode, 999, "area code");rangeCheck(prefix, 999, "prefix");rangeCheck(lineNumber, 9999, "line number");this.areaCode = areaCode;this.prefix = prefix;this.lineNumber = lineNumber;}private static void rangeCheck(int arg, int max, String name) {if(arg < 0 || arg > max) {throw new IllegalArgumentException(name + ": " + arg);}}@Overridepublic boolean equals(Object o) {if(o == this)return true;if(!(o instanceof PhoneNumber))return false;PhoneNumber pn = (PhoneNumber)o;return pn.lineNumber == lineNumber&& pn.prefix == prefix&& pn.areaCode == areaCode;}@Overridepublic PhoneNumber clone() {try {return (PhoneNumber) super.clone();} catch(CloneNotSupportedException e) {throw new AssertionError();}} }不可變類包括String,Integer,Short等包裝類。
而如果對象中包含的域引用了可變的對象,如:
public class Stack {private Object[] elements;private int size = 0;private static final int DEFAULT_INITAL_CAPACITY = 16;public Stack() {elements = new Object[DEFAULT_INITAL_CAPACITY];}public void push(Object e) {ensureCapacity();elements[size++] = e;}public Object pop() {if(size == 0) {throw new EmptyStackException();}Object result = elements[--size];elements[size] = null;return result;}private void ensureCapacity() {if(elements.length == size)elements = Arrays.copyOf(elements, 2 * size + 1);} }那么我們就要對引用對象進行深度賦值。
這里應該:
如果是Integer等不可變對象,則不用進行clone,如果是數組,包括普通類型數組,或者包裝類型數組,如int[],Integer[]則都要進行clone。
cloneable的問題導致我們不應該擴展這個接口,為了繼承而設計的類也不應該實現這個接口,由于它具有這么多缺點,專家級的程序員從來不去覆蓋clone方法, 也從來不去調用它,除非拷貝數組。
對于一個專門為繼承而設計的類,如果未能提供行為良好的受保護clone方法,它的子類就不可能實現Cloneable接口。
要想實現真正的深復制而不希望實現Cloneable接口,可行的辦法是實現Serializable接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆。不過因為序列化和反序列化,會造成一定的性能損失。
總結
以上是生活随笔為你收集整理的Effective Java之谨慎地覆盖clone(十一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Effectice Java之始终覆盖t
- 下一篇: Effective Java之使类和成员