java泛型系列 | 五、泛型、继承和子类型

如您所知,只要类型兼容,就可以将一种类型的对象分配给另一种类型的对象。 例如,您可以将一个 Integer 分配给一个Object,因为 Object 是 Integer 的超类型之一

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

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

public void someMethod(Number n) { /* ... */ }

someMethod(new Integer(10));   // OK
someMethod(new Double(10.1));   // OK

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

Box<Number> box = new Box<Number>();
box.add(new Integer(10));   // OK
box.add(new Double(10.1));  // OK

现在考虑以下方法:

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

它接受什么类型的参数? 通过查看它的签名,您可以看到它接受一个类型为 Box<Number> 的参数。 但是,这是什么意思? 您是否可以按预期传入 Box<Integer> 或 Box<Double>

答案是否定的,因为 Box<Integer> 和 Box<Double> 不是 Box<Number> 的子类型。在使用泛型编程时,这是一个常见的误解,但它是一个需要学习的重要概念。Box<Integer> 不是

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

 

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

1、泛型类和子类型

您可以通过继承或实现泛型类或接口的子类型。 一个类或接口的类型参数与另一个类或接口的类型参数之间的关系由 extends 和 implements 子句确定。以 Collections 类为例,

ArrayList<E> 实现了 List<E>,而 List<E> 继承了 Collection<E>。 所以 ArrayList<String> 是 List<String> 的子类型,List<String> 是 Collection<String> 的子类型。只要您不改

变类型参数,类型之间的子类型关系就会保留。

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

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

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

  • PayloadList<String,String>

  • PayloadList<String,Integer>

  • PayloadList<String,Exception>

 

 

posted @ 2021-09-16 16:08  meow_world  阅读(298)  评论(0)    收藏  举报