封裝設定屬性,一家人都要整整齊齊系列(1) JAVA泛型的實現原理
1.基本學過JAVA的人都知道一點泛型,明白常出現的位置和大概怎麼使用。在類上為:class 類名<T> {} 在方法上為:public <T> void 方法名 (T x){}就不再贅述了。
2.泛型就是將型別變成了引數去傳入,使得可以使用的型別多樣化,進而實現解耦。JAVA因為泛型是在1.5以後出現的,為了保持對以前版本的相容,使用了擦除的方法實現泛型。所以比起C++等在使用上限制較多。擦除是什麼呢,實際上就是一定程度無視了型別引數T,直接從T所在的類開始向上T的父類去擦除(或者說轉型?)比如:我呼叫泛型方法,傳了型別引數T進入方法內部,如果沒在宣告時做類似public T 方法名(T extends 某個父類 t){}這樣的宣告,在我的參
3.在泛型裡如下的例子無法成立 List<Number> list = new List<Integer>();因為在編譯器看來List<Number>不是List<Integer>的父類(我也不知道具體原因,誰知道告訴我下),雖然在我們看來Number是 Integer的父類,那麼他們組成的容器List應該有這種繼承關係。為了實現這種繼承關係,我們可以使用萬用字元?。這樣寫就可以了
4.還有無界萬用字元<?>,根據以上推論就知道其作用和限制了,它與不加泛型的List相比在於強調它是規定了某類的List,而不是Object類的List,只是我也不確定是什麼類。
以上部分轉載自https://www.cnblogs.com/taojinxuan/p/7222287.html
以下是我的個人見解:首先解決作者提出的問題:為什麼List<Number>不是List<Integer>的父類?
答:因為Java用的是單繼承模型,他已經有一個爸爸了
然後,總結一下,這篇部落格並沒有很好的排版,所以閱讀比較麻煩,為了讓作者的意圖更加明確地表達出來,我大概做一下整理。
我們可以通過<T extends ...>和<T super ...>的方式來設定上下限,也就是在編譯的時候根據“里氏代換原則”進行設定預設的型別。如果沒有設定上下限,就預設為Object。所謂的“擦除和轉型都是在邊界上發生的”就是這個意思。
然後作者說了get和add方法不能使用的問題,道理其實也是一樣的,一切建立在“里氏代換原則”上,在設定泛型方法時,會設定一個預設值,也就是所謂的“邊界”。add被禁止的情況下,因為子類有可能重寫父類的某些方法(個人理解),所以如果要執行對應的T.method()時,就會出現使用的方法不對的問題,因為不能保證所有的方法在所有子類中的實現時相同的。
接著是get被禁用的情況,因為只設置了下限,也就是子類,這樣如果在List中添加了父類,但是呼叫了一個子類所獨有的方法,但是父類並沒有這個方法,情況就會變得很尷尬。
基本就是這樣,後面我將會繼續探討當泛型和lambda表示式結合的非常有趣的情況,從今天開始,我要好好寫部落格了==!