跳到主要内容

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 定义上界,根据需求选择合适的关键字。