1 泛型概述
Java泛型在JSE 5.0提出。泛型,表示适用于更多的类型。类型参数化,使用一个类型参数,不指定确切的类型,在使用的时候指定类型,便可以不用只是因为类型不同而相同的代码。
2 泛型使用
2.1 泛型类
public class GenericClass<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
声明一个泛型类,在类名后面用<>扩起来泛型变量,需要用泛型变量表示的地方都用泛型变量。在Java的库中,E表示容器元素类型,T表示任意类型,K,V分别表示键值对的key,value。
2.2 泛型接口
public interface GenericInterface<T> {...}
声明一个泛型接口,与声明一个类名相似,在接口名后面用<>扩起来泛型变量E
2.3 泛型方法
public class GenericMethod {
//泛型方法
public <T> void add(T e) {}
}
声明一个泛型方法,需要在返回值前先引入泛型参数。泛型方法不是必须要在一个泛型类中,同样一个泛型类或接口中不是必须要有泛型方法。
3. 类型擦除
在Java的内部没有泛型类这个类型。泛型的实现机制实际上是类型擦除。类型擦除是编译器将参数类型替换成基本类型或者是限定类型,生成的泛型字节码仅有一份(不会因为类型不同而生成不同的代码)。在使用泛型的时候进行必要的类型检查或类型cast来保证最后获得的结果。
3.1 普通参数类型类
通过对泛型类GenericClass.java的反编译(javap -c -s GenericClass.class)
可以看到,在构造函数中会调用Object的构造函数。而且使用类型变量处,返回的变量都是java.lang.Object类型。说明在编译泛型类时,会将没有限定的泛型参数自动替换成Object(所有类的显示或隐式基类)
3.2 限定参数类型
//限定的参数类型
public class GenericWildcardClass<T extends Comparable<T>> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
当类型参数有限定时,使用限定的第一个类型代替参数类型。
3.3 泛型方法
由编译后方法的描述符可以看出,泛型方法中的类型参数同样遵循没有限定的泛型参数用Object代替参数,有限定的泛型用第一个限定类或接口代替参数
3.4 多态遇上泛型参数
public class GenericClass<T> {
...
public void setValue(T value) {
this.value = value;
}
public class GenericInheritanceClass extends GenericClass<Integer>{
...
}
public class GenericMain {
public static void main(String[] args) {
GenericClass<Integer> gic = new GenericInheritanceClass();
gic.setValue(new Integer(0));
}
}
gic 指向的是GenericClass类型,实际类型是GenericInheritanceClass。当调用setValue时,GenericClass中有的是setValue(Object)方法,而GenericInheritanceClass中类型擦除后是setValue(Integer)方法。 gic.setValue()应该调用的是GenericInheritanceClass中的方法,此时类型擦除与多态发生了冲突。编译器的解决方案是生成一个brige method, 也就是在GenericInheritanceClass中生成
public void setValue(Object value) {
setValue((Integer)value)
}
TODO