試想一個問題:
如果我們需要給一個超類的方法實現(xiàn)一種更強的功能,也就是加強版的超類,一般會怎么做?
繼承?
Too young too simple!
看看下面的例子:
當(dāng)我們需要一個類,需要HashSet類的所有方法,但是隨時需要知道在其創(chuàng)建到目前,已經(jīng)加入過多少元素,該如何實現(xiàn)?
一般使用繼承,覆蓋add()和addAll()方法,會顯得很合理:
1 public class InstrumentedHashSet<E> extends HashSet<E>{ 2 PRivate int mCount; 3 4 public int getmCount() { 5 return mCount; 6 } 7 @Override 8 public boolean add(E e) { 9 mCount ++;10 return super.add(e);11 }12 @Override13 public boolean addAll(Collection<? extends E> e) {14 mCount += e.size();15 return super.addAll(e);16 }17 }第9行和第14行進(jìn)行了對mCount的增加,那么真的像我們想象的那樣嗎?
1 public static void main(String[] args) { 2 InstrumentedHashSet<String> mHashSet = new InstrumentedHashSet<String>(); 3 4 ArrayList<String> mArrayList = new ArrayList<String>(); 5 mArrayList.add("1"); 6 mArrayList.add("2"); 7 mArrayList.add("3"); 8 9 mHashSet.addAll(mArrayList);10 System.out.println("總共插入了" + mHashSet.getmCount());11 12 }最后輸出:總共插入了9
Why?
其實是因為,在HashSet內(nèi)部的實現(xiàn)中,addAll()方法是調(diào)用了add()方法的,這一點雖然坑爹,但是沒有必要在文檔中說明。在這個類中,只要我們?nèi)サ鬭dd()的覆蓋,就可以良好的運行程序。
那么,問題來了,以后遇到這種需求的時候,還要不要用繼承呢?
可能你認(rèn)為這是個例,注意點就行了,那么,當(dāng)你想要使用繼承的時候,回答以下幾個問題:
1.如果這樣的父類在以后的版本中有改變呢?
2.如果父類加入了新的方法而自己卻沒有實現(xiàn)呢?
更甚至,你可能認(rèn)為我使用繼承,但是不覆蓋原有方法就安全了?考慮以下幾個問題:
1.如果超類添加了一個方法,而你給子類提供的方法的函數(shù)簽名碰巧與它相同,但是返回結(jié)果不同。那么,編譯器不會通過這個方法。
2.如果函數(shù)簽名和返回類型都相同,那不又是繼承了嗎?
幸運的是,有一種辦法可以解決以上問題,那就是看起來不起眼的 ——組合(復(fù)合)!
這樣,原有的類就成了新類的一個組件,新類中的每個示例方法都可以調(diào)用被包含現(xiàn)有類示例中的對應(yīng)方法,并返回它的結(jié)果,這被稱為“轉(zhuǎn)發(fā)”,新類中的方法被稱為轉(zhuǎn)發(fā)方法。
這樣的類非常穩(wěn)固,即使向現(xiàn)有的類增加了新的方法,也不會影響新的類。
只有當(dāng)子類是真正的超類的子類型的時候,才可以使用繼承,也就是說,必須存在“is-a”關(guān)系時候才適合使用繼承。
新聞熱點
疑難解答