public class Period { private final Date start; private final Date end; public Period(Date start, Date end) { // if (start.compareTo(end) > 0) { //不是線程安全的 // throw new IllegalArgumentException(); // } // // this.start = start; // this.end = end; this.start = new Date(start.getTime()); // 保護性拷貝是在檢查參數有效性以前進行。 this.end = new Date(end.getTime()); if (this.start.compareTo(this.end) > 0) { throw new IllegalArgumentException(); } } public Date start() { // return this.start; return (Date) this.start.clone(); } public Date end() { // return this.end; return (Date) this.end.clone(); } }
Period中被註釋掉的代碼,沒有采用保護性的拷貝。這樣的話,Period保存的是兩個引用,start和end返回的也是引用,那麼用戶能夠經過引用改變Period的狀態,致使start>end非法狀況出現。 java
注意到Period的構造方法中,保護性拷貝是在檢查參數有效性以前進行,爲何呢? 數組
這是爲了線程安全考慮。假如線程A恰好執行完參數有效性檢查,OK了,而後緊接的執行線程B,線程B改變了end的值,使start>end。輪到線程A執行了,有效性檢查OK了,開始拷貝..此時start和end的值已經不合法了。 安全
java中,重載方法的選擇是在編譯時決定的,跟類的多態不一樣。因此有些時候代碼行爲可能出乎咱們的意料。 this
好比以下代碼輸出的是三個"unknow",而不是分別輸出"set""list""unknow" spa
public class Test { public static String classify(Set s) { return "set"; } public static String classify(List l) { return "list"; } public static String classify(Collection c) { return "unknow"; } public static void main(String[] args) { // TODO Auto-generated method stub Collection[] c = new Collection[] { new HashSet(), new ArrayList(), new HashMap().values() }; for (Collection collection : c) { System.out.println(classify(collection)); // 重載方法的選擇是在編譯時決定的,由於collection的類型是Collection,因此選擇第三個重載方法。 } } }爲了使如上代碼按照咱們所想象的那樣工做,應該在Collection的重載方法中,用instanceof判斷參數的具體類型再作具體的邏輯。
對於重載方法,最好仍是別用了吧... 線程
看看java的ObjectOutputStream類,它的write方法沒有采用重載,而是採用了變形方法:writeBoolean(boolean) writeInt(int) writeLong(long)public Cheese[] getCheeses() { if (cheeseInstock.size() == 0) { return null; ...... } }這樣,用戶使用這個接口時,還要寫額外代碼去判斷數組是否爲null,這很容易出錯,建議應該返回0大小的數組而不是null。