泛型
泛型,字面意思将一个类泛化,让它适应多种情况(未知情况),使其更具兼容性扩展性。
public class HeapSort<T> {
T item;
public HeapSort(){
}
}
看代码,JAVA中的泛型定义和C++的很是类似,不过相比于C++泛型的强大,JAVA泛型却很是纠结。
因为目前,除了写数据结构之外,JAVA泛型几乎可有可无。这是因为JAVA的一个很重要的特性——擦除。
擦除
擦除,顾名思义泛型类中的某些东西被擦掉了,什么东西呢?就是泛型参数T的具体类型!
是的,JAVA程序运行时,JVM根本不知道你的泛型参数是什么类型,他只知道这是个Object。由于这个特性,在泛型类中做的一些相关于T类内部的所有操作都不会被接受,比如:
T t = new T();
T.a(); //a是T类中的实例方法
// 编译错误
由于擦除,就算你为这个HeapSort《T》创建了实例HeapSort《String》,JVM依然不知道你的T是String,它被想当然的向上转型成Object。这就意味着你的泛型类其实就是复合了Object的普通类。而C++则完全没有这种限制,C++的编译器会在编译期就检查泛型参数T到底是个什么类型,因此有关这个类型内部的所有操作都是正确的。
JAVA这么做是有意义的,在他们看来,因为泛型是1.5之后的性质,为了兼容1.5之前的各种开源库,使得他们不得不这么做(也就是擦除的由来),然并卵,我并不知道这么做的意义有多大=。=
有失去就会有补偿,对于泛型的补偿就是我们可以为泛型参数设置一个擦除的边界。
public class HeapSort<T extends Integer&List> {
}
这里extends有了新的作用,用于泛型参数的边界设定,意为T是某类和某接口的导出类。这样T就会向上转型成它的基类,因此可以使用基类的方法。
泛型同样可以用于方法,同时JAVA鼓励这样做,可以使用泛型方法完成的任务最好不要使用泛型类。
这里不得不说关于泛型方法的一个小福利——类型推断,在用赋值表达式调用泛型方法时,并不需要指明实参的类型,编译器会帮你判断这应该是个什么类型,比如这样:
public class HeapSort<T> {
public T a(T bb){
return null;
}
public static void main(String[] args) {
HeapSort<String> heap = new HeapSort<>();
String s = heap.a("dfwefg");
}
}
这使得泛型方法就像普通方法一样,然而其实这并没有什么卵用=。= T的类型已经声明过了,这很好猜。