博客
关于我
java_泛型结构模型整理
阅读量:248 次
发布时间:2019-03-01

本文共 3424 字,大约阅读时间需要 11 分钟。

官方教程:Java泛型类型通配符详解

在编写Java程序时,我们有时需要处理不同类型的对象,但又希望能够在不暴露具体类型的情况下进行操作。Java 提供了泛型类型通配符,用于实现这种需求。本文将详细介绍类型通配符的使用方法及其相关限制。


从特殊情况抽象出一般情况

在编写泛型类时,通常会遇到以下场景:

  • 类型参数的具体类型未知。
  • 需要处理不同类型的对象,但又希望保证其具有一些共同的属性或方法。

示例

假设我们有一个抽象类 Shape,其中定义了一个抽象方法 draw(Canvas c)。然后,具体实现该方法的类有 CircleRectangle。我们希望创建一个 Canvas 类,其中有一个 drawAll(List shapes) 方法,能够接受任何类型的 Shape 实例。

问题

原始代码中,drawAll() 方法的参数类型被限定为 List<Shape>,因此只能接受 Shape 类型的列表。然而,实际上,我们希望它能够接受任何 Shape 的子类类型的列表,例如 List<Circle>List<Rectangle>

解决方案

我们可以将 List 的通配符修改为 List<? extends Shape>。这样,drawAll() 方法就可以接受任何类型的 Shape 实例的列表。这种通配符被称为上界通配符


类型通配符的使用特点

1. 上界通配符(? extends Type

上界通配符允许我们指定通配符的上界,即通配符可以接受的具体类型及其子类。例如:

List
shapes = new ArrayList<>();shapes.add(new Circle());shapes.add(new Rectangle());

在这种情况下,shapes 列表可以包含 Shape 类型及其任意子类(如 CircleRectangle)。

2. 下界通配符(? super Type

下界通配符允许我们指定通配符的下界,即通配符只能接受某个具体类型或其父类。例如:

List
numbers = new ArrayList<>();numbers.add(new Integer(10));numbers.add(new Double(3.14));

在这种情况下,numbers 列表可以包含 Number 类型及其父类(如 Object)。

3. 无限定通配符(?

无限定通配符允许通配符接受任何类型,但在进行写操作时会带来潜在的类型安全风险。例如:

List
list = new ArrayList<>();list.add(new Object());Object obj = list.get(0);

这里,obj 的类型会被推断为 Object,但无法确保其实际类型是否与 List 中的元素类型一致。


类型通配符的实际应用

示例 1:使用上界通配符

考虑一个 Canvas 类,其中有一个 drawAll(List<? extends Shape> shapes) 方法。我们可以将任何类型的 Shape 实例的列表传递给这个方法:

List
circles = new ArrayList<>();circles.add(new Circle());drawAll(circles);

此时,shapes 的类型被推断为 List<Circle>,满足 Shape 的上界要求。

示例 2:使用下界通配符

考虑一个 Census 类,其中有一个 addRegistry(Map<String, ? extends Person> registry) 方法。我们可以将任意类型的 Person 实例的映射传递给这个方法:

Map
drivers = new HashMap<>();drivers.put("张三", new Driver());addRegistry(drivers);

此时,registry 的类型被推断为 Map<String, Driver>,满足 Person 的下界要求。


类型通配符的限制

1. 上界通配符的优点

  • 提供了类型的上界,确保通配符只能接受特定类型及其子类。
  • 在读操作时,可以安全地调用通配符类型的方法。

2. 上界通配符的缺点

  • 在写操作时,不能随意传递任意类型的实例。
  • 需要确保传入的实例类型是通配符类型的子类或本身。

示例

以下代码会导致编译错误:

List
shapes = new ArrayList<>();shapes.add(new Rectangle());

原因是 RectangleShape 的子类,满足上界要求。但如果尝试传入非 Shape 类型的实例,会导致错误。


实际案例:Pair 类的泛型方法

类定义

public class Pair
{ private T first; private T last; public Pair(T first, T last) { this.first = first; this.last = last; } public T getFirst() { return first; } public T getLast() { return last; } public void setFirst(T first) { this.first = first; } public void setLast(T last) { this.last = last; }}

使用示例

Pair
integerPair = new Pair<>(123, 456);Pair
stringPair = new Pair<>("test", "test");integerPair.setFirst(456);stringPair.setLast("test2");

说明

  • integerPair 的类型是 Pair<Integer>,只能存储 Integer 类型的对象。
  • setFirstsetLast 方法可以传递任意类型的实例,只要它们是目标类型的子类。

类型通配符的安全性

例子:上界通配符

public class TestExtends {    public static void main(String[] args) {        Pair
p = new Pair<>(123, 456); printGetValues(p); } static int add(Pair
p) { Number first = p.getFirst(); Number last = p.getLast(); return first.intValue() + last.intValue(); } static void printGetValues(Pair
p) { Object obj = p.getFirst(); System.out.println(obj.getClass().getName()); }}

说明

  • add 方法可以接受任何类型的 Number 实例的 Pair
  • printGetValues 方法只能打印 Pair 中的元素值,无法获取其具体类型。

总结

通过上述案例可以看出,类型通配符在Java 中提供了极大的灵活性。上界通配符允许我们指定通配符的上界,确保通配符只能接受特定类型及其子类。下界通配符则允许我们指定通配符的下界,确保通配符只能接受某个类型及其父类。无限定通配符虽然灵活,但需要谨慎使用,以避免类型安全问题。

在实际开发中,选择合适的通配符类型对于代码的可读性和维护性至关重要。同时,需要注意通配符的边界条件,以确保代码的类型安全。

转载地址:http://bozt.baihongyu.com/

你可能感兴趣的文章
oracle 监听器的工作原理
查看>>
oracle 行列转换
查看>>
oracle 行转列
查看>>
Oracle 表
查看>>
oracle 课堂笔记
查看>>
Oracle 返回结果集的 存储过程
查看>>
Oracle 递归
查看>>
Oracle 递归函数与拼接
查看>>
oracle 逻辑优化,提升高度,综合SQL上下文进行逻辑优化
查看>>
oracle 闪回关闭,关闭闪回即disable flashback的操作步骤
查看>>
oracle 限制用户并行,insert /*parallel */ 到不同用户,并行起不来的问题
查看>>
oracle--用户,权限,角色的管理
查看>>
Oracle-定时任务-JOB
查看>>
oracle.dataaccess 连接池,asp.net使用Oracle.DataAccess.dll连接Oracle
查看>>
oracle00205报错,Oracle控制文件损坏报错场景
查看>>
Oracle10g EM乱码之快速解决
查看>>
Oracle10g下载地址--多平台下的32位和64位
查看>>
Oracle10g安装了11g的ODAC后,PL/SQL连接提示TNS:无法解析指定的连接标识符
查看>>
oracle11g dataguard物理备库搭建(关闭主库cp数据文件到备库)
查看>>
Oracle11G基本操作
查看>>