基于《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(); } }