9.2.2 从泛型类派生子类

9.2.2 从泛型类派生子类

当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或从该父类派生子类,需要指出的是,当使用这些带泛型声明的接口、父类时不能再包含泛型形参例如,下面代码就是错误的。

1
2
3
//定义类A继承Appe类, Apple类不能跟泛型形参
public class A extends Apple<T>{
}

方法中的形参代表变量、常量、表达式等数据,本书把它们直接称为形参,或者称为数据形参

定义方法时可以声明数据形参,调用方法(使用方法)时必须为这些数据形参传入实际的数据;

与此类似的是,定义类、接口、方法时可以声明泛型形参,使用类、接口、方法时应该为泛型形参传入实际的类型

如果想从Apple类派生一个子类,则可以改为如下代码:

1
2
3
//使用 Apple类时为T形参传入String类型
public class A extends Apple<String>{
}

调用方法时必须为所有的数据形参传入参数值,与调用方法不同的是,使用类、接口时也可以不为泛型形参传入实际的类型参数,即下面代码也是正确的。

1
2
3
//使用 Apple类时,没有为T形参传入实际的类型参数
public class A extends Apple{
}

像这种使用Apple类时省略泛型的形式被称为原始类型(raw type)。

如果从Apple<String>类派生子类,则在Apple类中所有使用T类型的地方都将被替换成String类型,即它的子类将会继承到String getInfo()void setlnfo(String info)两个方法,如果子类需要重写父类的方法,就必须注意这一点。下面程序示范了这一点。

1
2
3
4
5
6
7
8
9
10
11
12
public class A1 extends Apple<String> {
// 正确重写了父类的方法,返回值
// 与父类Apple<String>的返回值完全相同
public String getInfo() {
return "子类" + super.getInfo();
}

// // 下面方法是错误的,重写父类方法时返回值类型不一致
// public Object getInfo() {
// return "子类";
// }
}

如果使用Apple类时没有传入实际的类型(即使用原始类型),java编译器可能发出警告:使用了未经检査或不安全的操作——这就是泛型检查的警告,读者在前一章中应该多次看到这样的警告。如果希望看到该警告提示的更详细信息,则可以通过为javac命令增加-Xlint unchecked选项来实现。此时,系统会把Apple<T类里的T形参当成Object类型处理。如下程序所示。

1
2
3
4
5
6
7
8
9
10
public class A2 extends Apple
{
// 重写父类的方法
public String getInfo()
{
// super.getInfo()方法返回值是Object类型,
// 所以加toString()才返回String类型
return super.getInfo().toString();
}
}

上面程序都是从带泛型声明的父类来派生子类,创建带泛型声明的接口的实现类与此几乎完全一样,此处不再赘述。