泛型

泛型

标签(空格分隔): java


没有使用泛型的List

如果没有使用泛型,List存放的是Object类型,因此可以向List中存放任何类型,不包括基本类型;在获得List里的数据时,由于返回的数据也是Object类型的,所以要进行强制类型转换。

List list = new ArrayList();
list.add(new String("test");
String str = (String) list.get(0);

在没有使用泛型时,这里存在2个问题:
1.如果在创建时定义List的类型为A,但是在添加元素时添加类型为B的数据,编译是能通过的,也就是存在类型不安全问题
2.在获得元素时,需要进行强制类型转换,意味着可能出现类型转换异常,因此加一个instanceof的判断似乎是应该要的。

使用泛型的List

定义时,在<>中指定类型,可以很好解决上诉的2个问题:
<>限制了List能存放的类型,当放入不同类型的数据时,编译不通过;
在获得元素时,get方法在内部会进行强制类型转换,不需要我们手写。

泛型类型

泛型的最大价值在于:在保证类型安全的前提下,把算法和数据类型解耦

泛型类:

在类的后面+<T>
当子类需要使用父类的类型参数时,在继承的时候要指定父类后面+<T>,这样子类就可以与父类共享一个T了。

泛型方法:

在权限关键字后加<T>,为该方法声明一个类型参数T;
可以使用T作为返回参数,定义在方法名前;
可以使用T作为传入参数,但更多时候结合反射传入T的类型信息,比如Class<T>,再使用获取类型信息的3种方法获取实例即可。
接口同样可以使用泛型,定义的方式和类是一样的。

通配符

使用?代替参数T,和使用T的区别就是,T在传进参数类型后就固定一个值了,而通配符不会固定,它在下一次传进别的类型的值时也是成立的。
通配符也存在一个问题,因为是使用?指定类型的,所以在取出元素时,无法事先知道元素的类型,解决的办法是使用泛型进行捕获,也就是将值赋予给泛型,因为通配符在运行时表示的类型肯定是具体的类型,将它附给泛型就可以进行具体的判断和操作了。

泛型边界

指的是为泛型参数指定范围,限定实例化泛型类时传入的具体类型,使用关键字superextends
可以使用多边界限制,不同的限制类型间使用&隔离。

泛型擦除

泛型代码在编译后,都会被擦除成原生类型,也就是用泛型指定的上界(没有指定的时候为Object)代替T所在的位置,实际上。Java在运行时,并不存在类型参数这一概念,类型的安全性的检查都是在类型参数擦除前做的。类型擦除会带来不少的问题,而之所以会这样设计,是为了兼容非泛化的类库。
当有多边界时,取最左边的类型参数为上界。

泛型限制

产生限制的原因:泛型类在运行时丢失了泛型信息。
限制:
1.类型参数是不能实例化对象的
因为当泛型信息被擦除后,实例化对象时并不能确定泛型所指定的上界类型是否有无参的构造函数。
private T t = new T(); //是不允许的
2.不能使用instanceof判断类型
3.不能捕获或者抛出泛型类对象
因为泛型类是不能继承或实现Throwable接口及子类的。

泛型擦除与多态的冲突

由于泛型擦除,动态绑定会失效,因为类型擦除会使子类覆盖父类的这个方法变成一个不同的方法。
但是在实际的使用中却可以正常的运行,java编译器会在子类中生成一个桥方法来解决这个问题。

桥方法

桥方法在权限后面使用关键字volatitle修饰,它的方法名和需要使用动态绑定的方法名是一样的,不同的是,输入类型和输出类型(假如有)都会变成Object(或者是指定的上限类型),这样方便擦除后传入参数,然后在这个方法内进行强制类型转换 ,把Object转变成动态绑定需要的类型,然后再用这个类型去调用动态绑定指定方法。

擦除总结

1.虚拟机中没有泛型,只有普通的类和方法
2.所有的类型参数都将被擦除成边界
3.为确保多态,必要时合成了桥方法
4.类型安全检查和类型转换是在编译时进行的,必要时插入额外的代码

另外,在一个容器中,如果指定了T的extends的上界或者super的下界,都不能向子类容器中添加父类的引用,而可以添加限定参数类型的子类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值