泛型,继承和子类型

Author Avatar
贾康 11月 11, 2016

正如你所知,如果一个类型适配另一个类型,那么我们可以用这个类型的对象给另一个类型的对象赋值,举例来说,因为Object是Integer的父类我们可以给一个Object对象一个Integer的值。

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

在面向对象的术语中,这叫做“是一个”的关系。既然Integer是一个Obejct,这个赋值就是被允许的。而且既然Integer是一个Number,所以以下代码也是正确的。

1
2
3
4
public void someMethod(Number n) { /* ... */ }
someMethod(new Integer(10)); // OK
someMethod(new Double(10.1)); // OK

这一点在泛型上也适用,声明一个泛型调用,以Number作为它的类型参数。这样如果使用适配Number的类型都可以作为类型参数。

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

现在我们考虑如下方法

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

它可以接收什么样的参数?通过方法声明,我们可以看出它只接受一个Box类型的参数,但是这意味着什么?是否和你期望的一样它可以接受Box或是Box?答案是不行,因为Box不是Box的子类型。
这在泛型编程中可能有些难理解,但是这是泛型编程的一个重点

虽然Integer是Number的子类,但是Box<Integer>并不是Box<Number>的子类。

需要注意:假设有A,B两个类,不管A,B是什么关系,MyClass<A>MyClass<B>都没有任何关系,MyClass<A>,MyClass<B>的共同父类是Object。
如果你想了解如何创建泛型间的父子关系,请参考通配符和子类型

###泛型类和子类型
我们可以通过继承或实现一个泛型类来创建它的子类型,两者的关系依赖于你是继承还是实现它。
以Collections类为例,ArrayList<E>实现了List<E>,List<E>继承了Collection<E>,所以说ArrayList<String>List<String>的子类型。既然我们没有变类型参数。所以他们之间的关系如下图所示:

假设我们现在想定义哦我们呢自己的list接口PayLoadList,它有一个可变的类型参数P,它的声明可能像这样:

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

以下的类都是List<String>类的子类。

  • PayloadList<String,String>
  • PayloadList<String,Integer>
  • PayloadList<String,Exception>

    下一页