Java 泛型中的继承与通配符
子类与父类都是泛型类的情况
在 Java 中,当子类和父类都是泛型类时,子类在继承父类时必须传递父类的类型参数。如果子类不是泛型类,而父类是泛型类,那么在子类继承时需要为父类的泛型指定具体的类型。
下面是一个泛型父类 Father<T>
:
package com.Generics;
public class Father<T> {
private T name;
public Father(T name) {
this.name = name;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
}
接着,我们定义一个泛型子类 Child<T>
,继承自 Father<T>
:
package com.Generics;
public class Child<T> extends Father<T> {
public Child(T name) {
super(name);
}
}
在主程序中,可以这样使用:
Child<String> child = new Child<>("sumingcheng");
System.out.println("child.getName(): " + child.getName());
child.setName("sumingcheng");
System.out.println("child.getName(): " + child.getName());
Child<Integer> child1 = new Child<>(100);
System.out.println("child1.getName(): " + child1.getName());
child1.setName(101);
System.out.println("child1.getName(): " + child1.getName());
使用泛型的好处是可以在传入参数时决定类型,减少重复代码,提高代码的灵活性。
泛型接口
我们还可以定义泛型接口 IPrinter<T>
以及其实现类 PrinterImpl<T>
:
package com.Generics;
public interface IPrinter<T> {
void print(T item);
}
package com.Generics;
public class PrinterImpl<T> implements IPrinter<T> {
@Override
public void print(T item) {
System.out.println("类型 " + item.getClass().getSimpleName() + ",值 " + item);
}
}
在主程序中使用:
IPrinter<String> stringPrinter = new PrinterImpl<>();
stringPrinter.print("sumingcheng");
IPrinter<Integer> integerPrinter = new PrinterImpl<>();
integerPrinter.print(12345);
使用 super
关键字定义通配符的下界
在泛型中,可以使用 super
关键字来定义通配符的下界,以便向集合中添加元素。例如:
List<? super Integer> list = new ArrayList<Number>();
list.add(10); // 允许
// list.add(new Object()); // 编译错误
// list.add(5.5); // 编译错误
在这个例子中,List<? super Integer>
表示可以是 Integer
或其父类型的列表,但只能添加 Integer
或其子类型的对象。这样可以确保类型安全,避免添加不兼容的类型。
注意事项
- 在继承泛型类时,务必明确指定类型参数,避免类型擦除导致的运行时错误。
- 使用泛型接口时,可以实现更灵活的代码,适用于多种类型的数据处理。
- 在使用通配符时,
super
定义下界,extends
定义上界,根据需求选择合适的关键字。