为什么需要泛型
泛型本质就是 “ 参数化类型 ”,泛型为我们在编译时指明了参数的类型。如果我们不使用泛型,那么不知道参数的类型,我们的做法可能就是强制类型转换,这样很容易会出现ClassCastException强制类型转换错误。但是使用了泛型,我们就可以在编译期捕获到类型转换错误,而不用等到运行期接受异常。如果我们不使用泛型,最终的结果就是到处都是Object和强制类型转换,代码的可阅读性极差。
泛型的擦除
在Java语言中泛型的实现策略是采用类型擦除,而这种方式成为伪泛型。
public class CaseTest {
public static void main(String[] args) {
List<String> strList = new ArrayList<String>();
List<Integer> iList = new ArrayList<Integer>();
}
}
CaseTest.class反编译后:
反编译CaseTest.class.jpg
说明:
可以发现java代码经过编译后的class文件,泛型类型都变回了原生类型。可以得到的结果就是java代码在编译期会将泛型代码内部的类型擦除;同时我们在泛型代码内部,也就无法获得任何有关泛型参数类型的信息了。
泛型擦除中方法重载问题
2.jpg说明:可以看出泛型在编译期会变回List<E>这样,重载的方法产生冲突了。所以编译期是不会通过的。。
泛型中协变
协变实际就是小范围的类型代替大范围的类型。我们可以使用<? extends T>实现了泛型的协变。
集合框架协变.jpg
可以看出java本身这种隐式的协变是不支持的,需要我们显式的指出这种小范围代替大范围的协变。
<? extends T>例子.jpg
泛型中逆变
逆变实际上就是大范围类型代替小范围类型。我们可以使用<? super T>实现了泛型的逆变。
集合框架逆变.jpg
可以看出java本身对这种隐式逆变是不支持的,我们可以显式地使用逆变。
<? super T>例子.jpg
基类劫持接口
public interface MyInterface<T> {
public void print(T t);
}
7.jpg
说明:可以发现编译不通过,会提示接口不可以实现超过1个的不同参数。
网友评论