Java学习点滴——泛型

基于《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 typeget

自限定类型

由于使用泛型时,其类型参数会被当作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();    
    }
}
相关文章
相关标签/搜索