Generics, Inheritance, and Subtypes
正如你所知,可以把一种对象类型赋值给另一种类型,只要他们是兼容的。例如,你可以把Integer对象赋值给Object。
Object someObject = new Object(); Integer someInteger = new Integer(10); someObject = someInteger; // OK
在面向对象技术中,这被称作“is a"关系。即一个Integer是一中Object,该赋值是允许的。同样,下面代码段也是有效的:
public void someMethod(Number n) { /* ... */ } someMethod(new Integer(10)); // OK someMethod(new Double(10.1)); // OK
上面的原则同样适用于泛型:
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<Number>的子类型。
这是泛型编程中经常出现的误解,这是一个很重要的值得学习的概念。
尽管Integer是Number的子类型,但是Box<Integer> 不是 Box<Number>的子类型
Note: 任何具体的类型A和B,如Number与Integer,MyClass<A>和MyClass<B>没有关系,不管A和B是否有关系。 MyClass<A>与 MyClass<B>的共同父类是Object。
当参量类型有关系时,如何在两个子泛型类之间建立像子类型之间的关系,请参考通配符和子类型。
泛型类与子类型化
通过子类型化一个类或是接口,你可以扩展或是实现它。一个类或接口的类型参量与另一个类或接口的类型参量的关系,由扩展或是实现的语句决定。
使用集合类Collections做例子: ArrayList<E>实现 List<E>;List<E>继承(扩展)Collection<E>。
因此,ArrayList<String>是List<String>的子类化,List<String>是Collection<String>的子类化。只要不改变类型参数,它们的子类型化关系是不变得。
Collections 体系例子
现在假设我们要定义自己的列表接口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>
PayloadList体系例子