Java泛型上界下界通配符举例分析

本篇内容主要讲解“Java泛型上界下界通配符举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java泛型上界下界通配符举例分析”吧!

创新互联公司专注于尼元阳网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供尼元阳营销型网站建设,尼元阳网站制作、尼元阳网页设计、尼元阳网站官网定制、微信小程序开发服务,打造尼元阳网络公司原创品牌,更为您提供尼元阳网站排名全网营销落地服务。

泛型,继承和子类

如你所知,只要类型兼容,就可以将一种类型的对象分配给另一种类型的对象。例如,你可以指定一个整数一个对象,因为对象是一个整数的超类型:

Object someObject = new Object();Integer someInteger = new Integer(10);someObject = someInteger; // 好

在面向对象的术语中,这被称为“是一种”关系。由于Integer 是一种Object,因此允许赋值。但是Integer也是一种Number,所以下面的代码也是有效的:

public void someMethod(Number n){/ * ... * /}someMethod(new Integer(10)); // 好someMethod(new Double(10.1)); // 好

泛型也是如此。您可以执行泛型类型调用,将Number作为其类型参数传递,如果参数与Number兼容,则允许任何后续的add调用:

Box box = new Box ();box.add(new Integer(10)); // 好box.add(new Double(10.1)); // 好

现在考虑以下方法:

public void boxTest(Box n){/ * ... * /}

它接受什么类型的论据?通过查看其签名,您可以看到它接受一个类型为Box的参数。但是,这是什么意思?您是否可以按照您的预期传递Box或Box?答案是“否”,因为Box和Box不是Box的子类型。

这是在使用泛型编程时一个常见的误解,也是一个需要学习的重要概念。

Box不是Box的子类型,即使Integer是Number的子类型。

注意:给定两个具体类型 A 和 B(例如,Number和Integer),MyClass 与 MyClass无关,无论 A 和 B 是否相关。MyClass 和 MyClass 的公共父是Object。

有关如何在类型参数相关时在两个泛型类之间创建类似子类型关系的信息,请参阅下面的通配符和子类型一节。

泛型类和子类型化

您可以通过扩展(extends)泛型类或实现(implements)泛型接口来对其进行子类型化。一个类或接口的类型参数与另一个类或接口的类型参数之间的关系由extends和implements子句确定。

使用Collections类作为示例,ArrayList 实现 List,List 扩展Collection。所以 ArrayList是List的子类型,它是Collection的子类型。只要不改变类型参数,就会在类型之间保留子类型关系。

显示Collection层次结构示例的图表:ArrayList是 List的子类型,二者都是Collection的子类型。

现在假设我们想要定义我们自己的列表接口PayloadList,它将可选值泛型类型参数P的与每个元素相关联。它的声明可能如下:

interface PayloadList extends List {void setPayload(int index, P val);...}

PayloadList的以下参数化是List的子类型:

PayloadListPayloadListPayloadList

PayLoadList层次结构的示意图:PayloadList是List的子类型,它是Collection的子类型。 在PayloadList的相同级别是PayloadList 和PayloadList

通配符和子类型

如 泛型,继承和子类一节中所述,泛型类之间或接口之间几乎并不因它们的类型参数而相关。但是,您可以使用通配符在泛型类或接口之间创建关系。

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

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

编写以下代码是合理的:

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

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

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

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

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

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

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

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

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

通配符使用指南

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

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

一个“In”变量

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

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

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

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

通配符指南:

使用extends关键字, 定义带有上界通配符的“in”变量。  使用super关键字,使用下界通配符定义“out”变量。  在可以使用Object类中定义的方法访问“in”变量的情况下,使用无界通配符。  在代码需要作为“in”和“out”变量访问变量的情况下,不要使用通配符。

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

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

class NaturalNumber {private int i;public NaturalNumber(int i) { this.i = i; }// ...}class EvenNumber extends NaturalNumber {public EvenNumber(int i) { super(i); }// ...}

请考虑以下代码:

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

因为List是List,您可以赋值le给ln。但是你不能使用ln将自然数添加到偶数列表中。列表中的以下操作是可能的:

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

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

到此,相信大家对“Java泛型上界下界通配符举例分析”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!


本文标题:Java泛型上界下界通配符举例分析
分享网址:
http://ybzwz.com/article/geohdc.html