本篇主要介绍 Java 中的 泛型 型变
当子类型关系出现在更加复杂类型中时,新类型中有着怎样的类型关系?
Java中是不允许 子类型的泛型类型对象 赋值给 父类型的泛型类型对象的
1.概述
先来看看一段代码
public static void main(String[] args) {
Integer age = 25;
Number number = age;
List<Integer> integerList = Arrays.asList(1, 2, 3);
List<Number> numberList = integerList;
}
我们都知道 Integer 是 Number的子类 上面代码中会有问题吗? 看着好像没啥问题
但是其实是不可以的
搞清楚上面的原因 先理解一下 基础类型和实参类型 : 例如对于 List<String>
, List
就是基础类型而这里的 String
就是实参类型。
然而在Java中 泛型的 实参类型的的父子关系 是不会传递到 泛型的 基础类型的
List<Integer> integerList = Arrays.asList(1, 2, 3);
// 也就是说 虽然 Integer是Number的子类 但是 List<Integer> 并不是 List<Number>的子类
List<Number> numberList = integerList; //所以编译器直接抛错了
又比如 有如下方法, 接受 List<Number>
类型 但是却只能传递
// 又比如 有入
public static void printList(List<Number> numberList) {
numberList.forEach(System.out::println);
}
public static void main(String[] args) {
List<Integer> integerList = Arrays.asList(1, 2, 3);
printList(integerList);//编译器抛错! 但是其实我们确实需要实现啊
}
2.如何解决
思考一下上面的的问题, 该如何解决呢? 其实就引入了 Java中的 泛型 型变的知识, 在Java中也称为 上下界
-
上限 : <? extends 类 >
-
下限: <? super 类 >
//这样就不会抛错了!!
public static void printList(List<? extends Number> numberList) {
numberList.forEach(System.out::println);
}
public static void main(String[] args) {
List<Integer> integerList = Arrays.asList(1, 2, 3);
//这样就不会抛错了!!
List<? extends Number> numberList = integerList;
printList(integerList);
}
2.2 上限 (泛型 协变)
上限 : <? extends 类 > 也称为 泛型 协变
有了它就可以 规定 泛型的基础类型的父子关系 从 实参类型来推倒
协变限制
当这样操作后 会带来协变的限制 就是在只允许取值操作 , 不允许 添加操作
你仔细想想 确实呢, 我可能给了你一个 List<Double>
但是你却想往里面添加 Integer类型 肯定是不行的, 所以 使用了 协变 则 只能获取 不能添加, 就算你添加 Object 也不行
2.3 下限( 泛型 逆变)
下限: <? super 类 > 也称为 泛型 逆变
前面我们都在看 协变的样例 下面来看看 逆变
static class Animal {
}
static class Dog extends Animal {}
List<Animal> animalList = Arrays.asList(new Animal(),new Animal());
List<Dog> dogList = animalList; //这里思考一下 好像肯定不行
// 肯定心想 List<Animal> 想被赋 List<Dog> 都不行 还得借助 协变 , 还想反过来? 哈哈
但是当我 添加了 ? super 直接就可以成功赋值了, 这就是 逆变, 它是把 实参类型的父子关系 直接反过来了 , 也就是说 现在 List<Animal> 是List<Dog> 的子类了 这就是 逆变
逆变限制
协变有限制, 逆变也有限制, 它会限制 只能去添加 不能去获取, 因为你并不知道获取的类型是 什么 , 因为它没有上限了 但是在Java中是可以 调用遍历方法 只不过都是Object类型
总结
本篇主要介绍了 Java 中的泛型的 基础类型的实参类型 以及它们的关系,总结如下:
-
Java中泛型的 实参类型 如果存在父子关系 但是 泛型的 基础类型 并不会拥有这种关系 如Integer 是 Number的子类
但是 List<Integer> 和 List<Number> 并没有关系 也不存在父子关系
-
要想把 泛型的 实参类型 传递到 泛型的基础类型中 需要有 协变 和 逆变 2种方式 就是 ? extends 和 ? super
-
协变 ? extends : 上限
List<? extends Number> numberList = doubleList
存在的限制就是 无法添加 只能获取元素 -
逆变 ? super : 下限
List<? super Dog> dogList = animalList;
存在的限制就是无法获取具体类型元素 只能获取到Object类型,
只能添加元素, 可以添加 下限和下限的子类 如上就是 Dog 和 Dog 的子类`
原文始发于微信公众号(Johnny屋):Java中泛型 型变 (协变 逆变)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/89725.html