Java -- 泛型类型的继承规则(四)
使用泛型类时,我们有必要了解一些泛型类之间有关继承和子类型的准则。先看要使用的代码示例:
class Basic {
public void f() {
System.out.println("f() int Basic");
}
public void g() {
System.out.println("g() int Basic");
}
}
class SubClass extends Basic {
public void f() {
System.out.println("f() in SubClass");
}
}
class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
super();
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public T getSecond() {
return second;
}
public void setSecond(T second) {
this.second = second;
}
}
这里定义了三个类,其中一个是泛型类,另外两个是子父类关系。
首先要明确的是,SubClass是Basic的子类,那Pair<SubClass>和Pair<Basic>之间存在继承关系吗?答案是否定的。实际上,无论类型变量T和S之间有什么关系,包括继承关系还是实现关系,Pair<T>和Pair<S>之间都不会有什么联系。如下的赋值,是非法的:
// Generic type speciality
Pair<SubClass> pairsub = new Pair<>(new SubClass(), new SubClass());
Pair<Basic> pairbasic = pairsub; // illegal:Type mismatch: cannot
// convert from Pair<SubClass> to
// Pair<Basic>
如果是数组这样做的话,会发生什么呢:
// Array speciality
SubClass[] sub = new SubClass[2];
sub[0] = new SubClass();
sub[1] = new SubClass();
Basic[] basic = sub;
basic[0] = new SubClass();
basic[1] = new Basic();// will throw java.lang.ArrayStoreException if
// you run
但由于数组有特殊的类别保护,最后一行的赋值语句会出现异常。
《Java core》中有一条准则,我们永远可以将参数化类型转换为一个原始类型。但我们要注意此时的类型错误:
// if you ignore generic type, it's just raw type, like:Pair, not
// Pair<Basic>.
Pair<SubClass> pairsub2 = new Pair<>(new SubClass(), new SubClass());
Pair raw = pairsub2; //Pair is a raw type. References to generic type Pair<T> should be parameterized
raw.setFirst(new File("a.txt")); // only cause a warning:Type safety: The method setFirst(Object) belongs to the raw type Pair.
//References to generic type Pair<T> should be parameterized
此时原始类型是以Objec为变量类型的,它可以存储任何类型的对象;显然,这与我们使用泛型参数化的意愿是相悖的。
当然,泛型类也具有普通类的继承和实现特性。Pair<T>可以继承BasicPair<T>,此时Pair<Basic>可以转化为BasicPair<Basic>:
class BasicPair<T> {
}
class Pair<T> extends BasicPair<T>{
private T first;
private T second;
public Pair(T first, T second) {
super();
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public T getSecond() {
return second;
}
public void setSecond(T second) {
this.second = second;
}
}