Java 泛型系列三:泛型中的继承规则与通配符
本文概述:
- 本文为 Java 泛型系列第三篇文章,文章重点:泛型对继承关系的破坏、 泛型通配符extends 使用中编译器对get/set 的限定、泛型通配符super 下界反转问题(本文精华之所在);
泛型类型的继承规则
-
环境准备:FuClass、ZiClass、Pair;
-
FuClass.java
package generic; public class FuClass { } -
ZiClass.java
package generic; public class ZiClass extends FuClass { }
-
-
Pair<父类> ma = Pair<子类> 报错,两者之间没有继承关系
-
Pair.java
-
-
泛型类可以继承或扩展自其它泛型类,比如说List 与 ArrayList
-
泛型类指定类型会破坏原有的继承关系
- A 继承 B,但Pair< A > 与 Pair 不具有继承关系
泛型:通配符类型 extends
-
安全访问数据
-
细节:
- 限定了实参的上界,可以自己留着,也可以向下传,但是不能向上传
- 通配符是用在方法上,不能用在类上
-
编译器对get/set 的限定
-
总结:限定上界用于安全访问数据
- extends 限定实参类型,用作读取数据;
- 一般不用于set 数据,
- 因为编译器只知道上界是什么(可以用上界去接收),但是不知道?具体代表什么,所以不允许set 数据
-
环境准备:FuClass.java、ZiClass.java
-
FuClass.java
package generic; public class FuClass { } -
ZiClass.java
package generic; public class ZiClass extends FuClass { }
-
-
关键代码:
-
完整测试代码:
package generic; public class Pair<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } public static void main(String[] args) { Pair<? extends FuClass> ma = new Pair<>(); //测试get 方法 FuClass fuClass = ma.getData(); ma.setData("name");//报错 } }
-
泛型:通配符 super
-
安全插入数据
-
super 使用过程:简单使用
- Pair.java 可看做是一容器
package generic; public class Pair<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } public static void test(Pair<? super ZiClass> p){ System.out.println(p.toString()); } public static void main(String[] args) { //泛型类在使用时,指定其泛型类型 Pair<ZiClass> ziClassPair = new Pair<>(); Pair<FuClass> fuClassPair = new Pair<>(); test(ziClassPair); test(fuClassPair); } } -
super 的难点问题:下界反转问题
-
super 在泛型中指定了实参的下界,比如说,某一方法参数类型为 容器类<? super A>,那么调用这个方法时:详见上文代码
- 实例化泛型类具体种类
- 只能传入类A 以及类A 的父类
-
但是,如果在使用时没有指定容器的具体泛型时,则会发生下界反转问题
-
现象:
- 只能传入类A 或者类A 的子类、孙类实例;
-
-
super 对于 get 的兼容性
- 只能确定从容器中拿到的一定是Object 的子类
package generic; public class Pair<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } public static void test(Pair<? super ZiClass> p){ System.out.println(p.toString()); } public static void main(String[] args) { Pair<? super ZiClass> pair = new Pair<>(); //测试get 方法 Object o = pair.getData(); //以下代码全数报错 FuClass f = pair.getData(); ZiClass z = pair.getData(); SunClass s = pair.getData(); } -
super 对 set 的兼容性
- 虽然说,编译器不知道到底会插入什么类型,只是知道插入的一定是ZiClass 本身或者ZiClass 的父类,但是不确定到底是什么,所以编译器不允许插入;但是,ZiClass 本身或者其子类一定可以安全地插入,因为可以安全转型,这就是多态的一大应用(容器里面装的是父类引用,那么,我们就将子类对象传给它!!!)
- 关键代码:
-