Java泛型之协变与逆变及extends与super选择

Java泛型中的协变与逆变是很重要的概念,也常被面试官问到。本篇文章将带你深入理解这些概念,并介绍有关extends和super的最佳实践。

什么是Java泛型中的协变和逆变?

在介绍协变和逆变之前,我们需要先了解两个术语: 子类型和超类型。子类型是指一个类派生自另一个类,而超类型是指另一个类派生自某一个类。这两个概念很重要,后面我们会经常用到。

在Java中,泛型支持协变和逆变。通俗点讲,协变是指“向上转型”,逆变是指“向下转型”。具体来说,协变支持超类型的引用指向子类型的对象,而逆变支持子类型的引用指向超类型的对象。这是因为Java泛型中,如果一个类是另一个类或接口的子类型,则相应的泛型也应该是可以兼容的。

Java泛型中extends和super的选择

Java中,有两种方法可以声明泛型类型的边界,即extends和super。extends表示泛型类型应该是其边界类型的子类型,而super表示泛型类型应该是其边界类型的超类型。在使用泛型时,我们需要根据具体情况来选择使用哪种方式。

使用extends

在定义泛型时,如果希望只接受某个类及其子类作为泛型类型参数,就可以使用extends关键字。例如:

public class Box<T extends Number> {
  private T t;

  public void set(T t) {
    this.t = t;
  }

  public T get() {
    return t;
  }
}

在这个Box类中,我们使用了extends关键字来限制泛型类型T必须是Number及其子类类型。这意味着,我们可以使用任何Number的子类实例来创建Box对象。例如:

Box<Integer> integerBox = new Box<Integer>();

extends关键字的使用场景包括:

  • 如果希望某个泛型类型参数只能接受其边界类型及其子类型。
  • 如果希望某个方法返回的类型是某个泛型类型参数的子类型。

使用super

和extends相反,如果希望只接受某个类及其超类作为泛型类型参数,就可以使用super关键字。例如:

public class Box<T super Number> {
  private T t;

  public void set(T t) {
    this.t = t;
  }

  public T get() {
    return t;
  }
}

在这个Box类中,我们使用了super关键字来限制泛型类型T只能是Number及其父类类型。这意味着,我们可以使用任何Number的父类实例来创建Box对象。例如:

Box<Object> objectBox = new Box<Object>();

super关键字的使用场景包括:

  • 如果希望某个泛型类型参数只能接受其边界类型及其超类。
  • 如果希望把某个泛型类型参数的超类型传递给某个方法。

两个示例说明

为了深入理解协变和逆变,我们来看两个示例。

示例1: 协变

假设我们有一个Shape类和一个Circle类,Circle类是Shape类的子类。现在我们需要将Circle类的实例添加到一个List中。我们可以这样定义这个List:

List<? extends Shape> shapes = new ArrayList<Circle>();

这个使用了extends关键字的定义表明,shapes可以指向一个List对象,但也可以指向一个List、List等其他类型的对象。这意味着,我们可以向shapes添加任何Shape类及其子类的实例。

shapes.add(new Circle());
shapes.add(new Shape());

示例2: 逆变

假设我们有一个Comparator接口,其中有一个compare方法:

public interface Comparator<T> {
  public int compare(T o1, T o2);
}

现在我们需要在一个GeometricShape类中实现一个Comparator接口的compare方法。由于Circle类是GeometricShape类的子类,我们希望能够使用一个比较圆形的比较器来比较GeometricShape类的实例。我们可以这样定义比较器:

public class CircleComparator implements Comparator<Circle> {
  public int compare(Circle c1, Circle c2) {
    // ...
  }
}

但这个比较器无法在GeometricShape类中实际使用,因为在Comparator接口和CircleComparator类之间不存在任何继承关系。为了解决这个问题,我们可以在GeometricShape类中使用一个接受Comparator<? super T>类型参数的sort()方法:

public abstract class GeometricShape {
  public abstract void draw();

  public static <T extends GeometricShape> void sort(List<T> shapes, Comparator<? super T> comparator) {
    // ...
  }
}

由于使用了super关键字,这个sort()方法可以接受任何比较器,只要它可以比较T的超类型。这意味着,我们可以这样调用我们的sort()方法:

GeometricShape.sort(shapes, new Comparator<Circle>() {
  public int compare(Circle c1, Circle c2) {
    // ...
  }
});

这里的sort()方法参数中,shapes是一个List,而Comparator的类型是Comparator<? super T>,T是GeometricShape。这是因为,我们希望sort()方法接受的比较器类型是GeometricShape的超类型,所以我们采用了super关键字。

结论

Java泛型中的协变和逆变是很重要的概念,也常被面试官问到。本篇文章介绍了什么是协变和逆变,并介绍了使用extends和super的最佳实践。请务必根据具体的场景,选择正确的关键字来定义泛型类型的边界。同时,也要时刻记得在使用协变和逆变时,尽可能地让泛型类型参数更加通用,以便兼容更多的子类型和超类型。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java泛型之协变与逆变及extends与super选择 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 【图像编辑】三款图像编辑软件photoshop、affinityphoto、…

    【图像编辑】三款图像编辑软件photoshop、affinityphoto、gimp 图像编辑软件是每位设计师都必备的工具之一,因为它们可以对照片、图片和其他艺术品进行编辑和处理。在市场上,有很多优秀的图像编辑软件可供使用。在这篇文章中,我们将介绍三款最流行的图像编辑软件——Photoshop、Affinity Photo和GIMP。 Photoshop P…

    其他 2023年3月28日
    00
  • 博本G神G16a值得买吗?博本G神G16a RX560游戏本性能全面图解评测

    很抱歉,由于我是一个文本模型,无法提供关于具体产品的图解评测。我建议您查阅相关的评测文章或视频,以获取关于博本G神G16a RX560游戏本性能的详细信息。

    other 2023年10月17日
    00
  • 如何快速合并多个txt文本内容

    如何快速合并多个txt文本内容 在日常生活和工作中,我们常常需要将多个txt文本内容进行合并。如果手工逐一复制粘贴是非常耗时和低效的,而且容易出错。那么如何才能快速合并多个txt文本内容呢?本文将介绍三种方法。 方法1:使用CMD命令 打开CMD命令提示符; 进入需要合并的txt文本所在的文件夹; 输入如下指令: cmdcopy *.txt newfile.…

    其他 2023年3月28日
    00
  • 变量、函数、类的命名规则

    下面是变量、函数、类的命名规则的完整攻略。 变量的命名规则 变量的命名要符合以下规则: 变量名必须以字母或下划线(_)开头。 变量名只能包含字母、数字和下划线(_),不能包含其他字符。 变量名不能以数字开头。 变量名应该使用小写字母,并且采用下划线分割单词,以提高可读性。 例如: # 正确的变量命名 x = 1 name = "Jack"…

    other 2023年6月27日
    00
  • SpringBoot读取properties文件配置项过程解析

    SpringBoot读取properties文件配置项过程解析 在SpringBoot中,我们可以通过 .properties 文件来配置应用的相关参数,这些配置项可以用来设置一些基本的参数,比如应用所使用的数据库信息、日志级别、端口号等等。 配置文件位置 在SpringBoot应用程序中,配置文件的位置默认情况下是在 src/main/resources …

    other 2023年6月25日
    00
  • mysql-sql索引性能-asc与desc

    MySQL SQL索引性能:ASC与DESC的完整攻略 在MySQL中,索引是提高查询性能的重要手段之一。而在使用索引时,我们还需要考虑到索引的排序方式,即ASC(升序)和DESC(降序)。本文将介绍MySQL SQL索引性能中ASC与DESC的完整攻略,包括索引的排序方式对查询性能的影响、如何选择索引排序方式以及示例说明。 索引的排序方式对查询性能的影响 …

    other 2023年5月8日
    00
  • win10预览版10147自制中文iso镜像下载地址

    Win10预览版10147自制中文ISO镜像下载攻略 简介 Win10预览版10147是微软的操作系统的一个早期版本,该版本包含了一些新的功能和改进。本攻略将详细介绍如何下载自制的中文ISO镜像文件。 步骤 步骤一:准备工作 在开始下载之前,确保你已经满足以下要求:- 一台可靠的互联网连接的计算机。- 足够的存储空间来保存ISO镜像文件。 步骤二:查找下载地…

    other 2023年8月4日
    00
  • Dojo Javascript 编程规范 规范自己的JavaScript书写

    Dojo JavaScript 编程规范:规范自己的 JavaScript 书写 在编写 JavaScript 代码时,遵循一致的编程规范可以提高代码的可读性、可维护性和可扩展性。Dojo JavaScript 编程规范是一套被广泛接受的规范,下面将详细介绍如何规范自己的 JavaScript 书写。 1. 命名规范 使用驼峰命名法(camelCase)来命…

    other 2023年8月8日
    00
合作推广
合作推广
分享本页
返回顶部