基於《Java編程思想》第四版java
雖然Java的泛型在語法上和C++相比是相似的,但在實現上二者是全然不一樣的。編程
Java只須要一個<>
就可定義泛型。在<>
中可使用任意符合Java語法要求的字符做爲類型的標識,能夠定義泛型類、泛型接口、泛型方法等。函數
class A<T>{ T a; public <Q> void foo(Q a){ } } interface B<T>{ void foo(T a); }
Java的泛型並不像C++那樣是在編譯時根據須要按照模板實例化對應的類。好比下面這段C++代碼,會以A
爲模板實例化兩個類。this
template<typename T> class A { public: A(){} T a; }; int main() { A<int> a; A<float> b; return 0; }
查看彙編能夠證明,調用的是兩個不一樣類的構造函數code
0x0000000000400545 <+15>: callq 0x40056c <A<int>::A()> 0x0000000000400551 <+27>: callq 0x400578 <A<float>::A()>
Java中全部類都繼承自Object
,任意類對象均可以向上轉型後,使用Object
變量存儲其引用。基於這一點,Java的泛型實現時其實只有一種類型。如下兩個類實際是等同的對象
class A<T>{ T a; } class A{ Object a; }
當使用反射機制獲取泛型類的信息時,能夠發現class A<T>
實際就是class A
繼承
public static void main(String[] args) { A<Integer> a = new A(); Field[] f = a.getClass().getDeclaredFields(); System.out.println(Arrays.toString(f)); } // 輸出爲 [java.lang.Object A.a]
由此咱們也能夠知道爲何下面這段代碼老是輸出same class
接口
public static void main(String[] args) { A<Integer> a = new A(); A<Double> b = new A(); if( a.getClass() == b.getClass() ){ System.out.println("same class"); } }
由於基礎類型並不繼承自Object
,因此Java的泛型是不支持基礎類型的。若是這麼作了,就會獲得一個錯誤提示Type argument cannot be of primitive type
。get
由於使用泛型時,其類型參數會被當作Object
來處理,因此編譯器就沒法感知真實類型的方法了。
好比下面這段代碼,就沒法經過編譯編譯器
class A{ public void foo(){ System.out.println("A.foo()"); } } class B<T>{ T a; B(T a){ this.a = a; } public bar(){ a.foo(); // 此處會提示編譯錯誤,Object類型不存在foo()方法 } }
此時必須將泛型類B
的類型參數作限定,讓編譯器能從限定中獲取到足夠的信息去判斷類型參數是存在foo()
方法的。
class B<T extends A>{ T a; B(T a){ this.a = a; } public bar(){ a.foo(); } }