泛型通配符
在泛型代码中,称为通配符的问号(?)表示未知类型,通配符可用于各种情况:作为参数、字段或局部变量的类型,有时作为返回类型(尽管更好的编程实践是更加具体),通配符从不用作泛型方法调用、泛型类实例创建或超类型的类型参数。
以下部分更详细地讨论通配符,包括上界通配符、下界通配符和通配符捕获。
上界通配符你可以使用上界通配符来放宽对变量的限制,例如,假设你要编写一个适用于List
要声明一个上界通配符,请使用通配符("?"),后跟extends关键字,后跟上界,请注意,在此上下文中,extends在一般意义上用于表示“extends”(如在类中)或“implements”(如在接口中)。
要编写适用于Number和Number的子类型列表的方法,例如Integer、Double和Float,你可以指定List<?extends Number>,List
考虑以下process方法:
public static void process(List extends Foo> list) { /* ... */ }
上界通配符 extends Foo>,其中Foo是任何类型,匹配Foo和Foo的任何子类型,process方法可以像Foo类型一样访问列表元素:
public static void process(List extends Foo> list) { for (Foo elem : list) { // ... } }
在foreach子句中,elem变量遍历列表中的每个元素,现在可以在elem上使用Foo类中定义的任何方法。
sumOfList方法返回列表中数字的总和:
public static double sumOfList(List extends Number> list) { double s = 0.0; for (Number n : list) s += n.doubleValue(); return s; }
以下代码使用Integer对象列表打印sum = 6.0:
Listli = Arrays.asList(1, 2, 3); System.out.println("sum = " + sumOfList(li));
Double值列表可以使用相同的sumOfList方法,以下代码打印sum = 7.0:
List无界通配符ld = Arrays.asList(1.2, 2.3, 3.5); System.out.println("sum = " + sumOfList(ld));
使用通配符(?)指定无界通配符类型,例如List>,这称为未知类型的列表,有两种情况,无界通配符是一种有用的方法:
如果你正在编写可以使用Object类中提供的功能实现的方法。
当代码使用泛型类中不依赖于类型参数的方法时,例如,List.size或List.clear,事实上,经常使用Class>,因为Class
考虑以下方法,printList:
public static void printList(List
printList的目标是打印任何类型的列表,但它无法实现该目标 — 它只打印一个Object实例列表,它不能打印List
public static void printList(List> list) { for (Object elem: list) System.out.print(elem + " "); System.out.println(); }
因为对于任何具体类型A,List是List>的子类型,你可以使用printList打印任何类型的列表:
Listli = Arrays.asList(1, 2, 3); List ls = Arrays.asList("one", "two", "three"); printList(li); printList(ls);
在本课程的示例中使用了Arrays.asList方法,此静态工厂方法转换指定的数组并返回固定大小的列表。
重要的是要注意List和List>是不一样的,你可以将Object或Object的任何子类型插入List,但是你只能在List>中插入null,通配符使用指南部分提供了有关如何确定在给定情况下应使用哪种通配符(如果有)的更多信息。
下界通配符上界通配符部分显示上界通配符将未知类型限制为该类型的特定类型或子类型,并使用extends关键字表示,以类似的方式,下界通配符将未知类型限制为该类型的特定类型或超类型。
使用通配符(?)表示下界通配符,后跟super关键字,后跟下界: super A>。
你可以指定通配符的上界,也可以指定下界限,但不能同时指定两者。
假设你要编写一个将Integer对象放入列表的方法,为了最大限度地提高灵活性,你希望该方法可以处理List
要编写适用于Integer和Integer超类型列表的方法,例如Integer、Number和Object,你可以指定List super Integer>,List
以下代码将数字1到10添加到列表的末尾:
public static void addNumbers(List super Integer> list) { for (int i = 1; i <= 10; i++) { list.add(i); } }通配符和子类型
如泛型、继承和子类型中所述,泛型类或接口不相关,仅仅因为他们的类型之间存在关系,但是,你可以使用通配符在泛型类或接口之间创建关系。
给定以下两个常规(非泛型)类:
class A { /* ... */ } class B extends A { /* ... */ }
编写以下代码是合理的:
B b = new B(); A a = b;
此示例显示常规类的继承遵循此子类型规则:如果B扩展A,则B类是A类的子类型,此规则不适用于泛型类型:
List lb = new ArrayList<>(); List la = lb; // compile-time error
假设Integer是Number的子类型,List
虽然Integer是Number的子类型,但List
为了在这些类之间创建关系以便代码可以通过List
List extends Integer> intList = new ArrayList<>(); List extends Number> numList = intList; // OK. List extends Integer> is a subtype of List extends Number>
因为Integer是Number的子类型,而numList是Number对象的列表,所以intList(Integer对象列表)和numList之间现在存在关系,下图显示了使用上界和下界通配符声明的多个List类之间的关系。
上一篇:类型推断 下一篇:泛型通配符捕获和Helper方法文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72943.html
Java™ 教程 Java教程是为JDK 8编写的,本页面中描述的示例和实践没有利用在后续版本中引入的改进。 Java教程是希望使用Java编程语言创建应用程序的程序员的实用指南,其中包括数百个完整的工作示例和数十个课程,相关课程组被组织成教程。 覆盖基础知识的路径 这些教程以书籍的形式提供,如Java教程,第六版,前往Amazon.com购买。 入门 介绍Java技术和安装Java开发软件并使用...
泛型通配符捕获和Helper方法 在某些情况下,编译器会推断出通配符的类型,例如,列表可以定义为List,但是在评估表达式时,编译器会从代码中推断出特定类型,此场景称为通配符捕获。 在大多数情况下,你不必担心通配符捕获,除非你看到包含短语capture of的错误消息。 WildcardError示例在编译时产生捕获错误: import java.util.List; public class ...
泛型通配符使用指南 学习使用泛型编程时更困惑的一个方面是确定何时使用上界通配符以及何时使用下界通配符,此页面提供了设计代码时要遵循的一些准则。 对于本文的讨论,将变量看作提供的两个功能之一是有帮助的: 一个In变量 in变量向代码提供数据,想象一下带有两个参数的复制方法:copy(src, dest),src参数提供要复制的数据,因此它是in参数。 一个Out变量 out变量保存数据以供其他地方使...
泛型的限制 要有效地使用Java泛型,必须考虑以下限制: 无法使用基元类型实例化泛型类型 无法创建类型参数的实例 无法声明类型为类型参数的静态字段 无法对参数化类型使用强制类型转换或instanceof 无法创建参数化类型的数组 无法创建、捕获或抛出参数化类型的对象 无法重载将每个重载的形式参数类型擦除为相同原始类型的方法 无法使用基元类型实例化泛型类型 考虑以下参数化类型: class P...
泛型、继承和子类型 如你所知,只要类型兼容,就可以将一种类型的对象分配给另一种类型的对象,例如,你可以将Integer分配给Object,因为Object是Integer的超类型之一: Object someObject = new Object(); Integer someInteger = new Integer(10); someObject = someInteger; // OK ...
阅读 3735·2021-11-25 09:43
阅读 2168·2021-11-23 10:13
阅读 803·2021-11-16 11:44
阅读 2345·2019-08-29 17:24
阅读 1357·2019-08-29 17:17
阅读 3464·2019-08-29 11:30
阅读 2549·2019-08-26 13:23
阅读 2328·2019-08-26 12:10