Java语法糖之泛型

2018-10-06  本文已影响11人  sunpy

为什么需要泛型

泛型本质就是 “ 参数化类型 ”,泛型为我们在编译时指明了参数的类型。如果我们不使用泛型,那么不知道参数的类型,我们的做法可能就是强制类型转换,这样很容易会出现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个的不同参数。

上一篇 下一篇

猜你喜欢

热点阅读