Java 泛型之上界下界通配符

栏目: Java · 发布时间: 5年前

内容简介:Java教程是为JDK 8编写的。本页描述的示例和实践没有利用后续版本中引入的改进。如 泛型,继承和子类型中所述,泛型类或接口仅仅因为它们的类型之间存在关系而无关。但是,您可以使用通配符在泛型类或接口之间创建关系。给定以下两个常规(非泛型)类:

Java 泛型之上界下界通配符

Java教程是为JDK 8编写的。本页描述的示例和实践没有利用后续版本中引入的改进。

通配符和子类型

如 泛型,继承和子类型中所述,泛型类或接口仅仅因为它们的类型之间存在关系而无关。但是,您可以使用通配符在泛型类或接口之间创建关系。

给定以下两个常规(非泛型)类:

class A { /* ... */ }
    class B extends A { /* ... */ }

编写以下代码是合理的:

B b = new B();
    A a = b;

此示例显示常规类的继承遵循此子类型规则:如果B扩展A,则类B是类A的子类型。此规则不适用于泛型类型:

List<B> lb = new ArrayList<>();
List<A> la = lb;   //编译时错误

鉴于 IntegerNumber 的子类型, List<Integer>List<Number> 之间的关系是什么?

Java 泛型之上界下界通配符

公共父类是 List<?>

该图表显示 List<Number>List<Integer> 的公共父级是未知类型的 List .

尽管 IntegerNumber 的子类型,但 List<Integer> 不是 List<Number> 的子类型,实际上,这两种类型不相关。 List<Number>List<Integer> 的公共父是 List<?>

上界(extends)的通配符与下界(super)通配符

上界(extends)的通配符意即 该类的父类中包含或本身是指定类 .

下界(super)通配符意即 该类的子类中包含或本身是指定类 .

为了在这些类之间创建关系以便代码可以通过 List<Integer> 的元素访问 Number 的方法,请使用上界的通配符:

List<? extends Integer> intList = new ArrayList<>();
List<? extends Number>  numList = intList;  // OK, List<?extends Integer>是 List< ? extends Number>的子类型

因为 IntegerNumber 的子类型,而 numListNumber 对象的列表,所以 intList (是一个Integer对象列表)和 numList 之间现在存在关系。下图显示了使用上限和下限通配符声明的多个 List 类之间的关系。

Java 泛型之上界下界通配符

几个通用List类声明的层次结构。

图表显示 List<Integer>List <? extends Integer>List<?super Integer> 的子类型。 List<? extends Integer>List<? extends Number> 的子类型,它是 List <?> 的子类型。 List<Number>List <?super Number>List<? extends Number> 的子类型。 List<? super Number>List <? super Integer> 的子类型, ft且都是 List<?> 的子类型。

通配符使用指南

学习使用泛型编程时,更令人困惑的一个方面是确定何时使用上限有界通配符以及何时使用下限有界通配符。本文提供一些设计代码时要遵循的一些准则。

为讨论方便,认为变量具备两个功能:

一个“In”变量

“in”变量向代码提供数据。想象一下带有两个参数的复制方法:copy(src,dest)。该SRC参数提供的数据被复制,因此它是“in”参数。

一个“Out”变量

“out”变量保存数据以供其他地方使用。在复制示例中,copy(src,dest),dest参数接受数据,因此它是“out”参数。

当然,一些变量既用于“in”又用于“out”目的 - 这种情况也在本文中也用到了。

在决定是否使用通配符以及适合使用哪种类型的通配符时,可以使用“in”和“out”原则。以下列表提供了遵循的准则:

通配符指南:

extends
super
Object

这些指南不适用于方法的返回类型。应该避免使用通配符作为返回类型,因为它强制 程序员 使用代码来处理通配符。

List<? extends ...> 可以被非正式地认为是只读的,但这不是一个严格的保证。假设您有以下两个类:

class NaturalNumber {

    private int i;

    public NaturalNumber(int i) { this.i = i; }
    // ...
}

class EvenNumber extends NaturalNumber {

    public EvenNumber(int i) { super(i); }
    // ...
}

请考虑以下代码:

List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35));  // compile-time error //编译时错误

因为 List<EvenNumber>List<? extends NaturalNumber> ,您可以赋值 leln 。但是你不能使用 ln 将自然数添加到偶数列表中。列表中的以下操作是可能的:

  • 您可以添加null。
  • 你可以调用清除。
  • 您可以获取迭代器并调用remove。
  • 您可以捕获通配符并写入从列表中读取的元素。

你可以看到 List<? extends NaturalNumber> 在严格意义上不是只读的,但您可能会这样想,因为您无法存储新元素或更改列表中的现有元素。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大数据时代的算法:机器学习、人工智能及其典型实例

大数据时代的算法:机器学习、人工智能及其典型实例

刘凡平 / 电子工业出版社 / 2017-1 / 49

《大数据时代的算法:机器学习、人工智能及其典型实例》介绍在互联网行业中经常涉及的算法,包括排序算法、查找算法、资源分配算法、路径分析算法、相似度分析算法,以及与机器学习相关的算法,包括数据分类算法、聚类算法、预测与估算算法、决策算法、关联规则分析算法及推荐算法。《大数据时代的算法:机器学习、人工智能及其典型实例》涉及的相关算法均为解决实际问题中的主流算法,对于工作和学习都有实际参考意义。 《......一起来看看 《大数据时代的算法:机器学习、人工智能及其典型实例》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试