泛型是Java语言中一项强大的特性,它允许在定义类、接口或方法时使用类型参数,从而在编译阶段进行类型检查,避免类型转换异常,提高代码的类型安全性和可读性,泛型类的定义是泛型机制的核心应用之一,本文将详细介绍如何在Java中定义泛型类,包括其语法结构、类型参数的使用、限制条件以及实际应用场景。

泛型类的定义语法与基本使用
在Java中,定义泛型类需要在类名后面紧跟一对尖括号<>,并在尖括号内声明一个或多个类型参数,类型参数通常使用大写字母表示,如T(Type)、E(Element)、K(Key)、V(Value)等,这是一种约定俗成的命名规范,目的是提高代码的可读性。
定义一个简单的泛型类Box,用于存储任意类型的对象:
public class Box<T> {
private T content; // 使用类型参数T声明成员变量
// 构造方法
public Box(T content) {
this.content = content;
}
// 获取内容
public T getContent() {
return content;
}
// 设置内容
public void setContent(T content) {
this.content = content;
}
}
上述代码中,<T>声明了一个类型参数T,Box类中的成员变量content、构造方法的参数以及getContent()和setContent()方法的返回值和参数类型均使用了T。T在编译时代表一个未知的类型,只有在实际使用Box类时才会指定具体的类型。
使用泛型类时,需要在类名后面指定具体的类型参数,
public class Main {
public static void main(String[] args) {
// 创建Box实例,指定类型参数为String
Box<String> stringBox = new Box<>("Hello, Generics!");
String content = stringBox.getContent(); // 无需类型转换
System.out.println(content); // 输出:Hello, Generics!
// 创建Box实例,指定类型参数为Integer
Box<Integer> integerBox = new Box<>(123);
int num = integerBox.getContent(); // 自动拆箱,无需类型转换
System.out.println(num); // 输出:123
}
}
通过指定类型参数,编译器会在编译阶段检查类型的一致性,如果尝试将Box<String>的content设置为非String类型(如Integer),编译器会直接报错,避免了运行时的ClassCastException。
类型参数的限制
泛型类的类型参数可以是任意类型,但有时需要对类型参数的范围进行限制,以确保类型参数具备某些特定的方法或属性,Java中通过extends关键字对类型参数进行约束,这里的extends不仅限于继承类,还可以用于实现接口。
定义一个泛型类NumericBox,要求类型参数必须是Number类或其子类(如Integer、Double等):
public class NumericBox<T extends Number> {
private T value;
public NumericBox(T value) {
this.value = value;
}
// 获取value的doubleValue方法(Number类中的方法)
public double getDoubleValue() {
return value.doubleValue();
}
}
上述代码中,<T extends Number>表示类型参数T必须是Number或其子类。NumericBox可以接受Integer、Double等类型,但不能接受String或Object等非Number类型,否则编译器会报错。
如果需要类型参数同时满足多个约束(如既继承类又实现接口),可以使用&符号分隔,

public interface Serializable {}
public class MyClass implements Serializable {}
// 要求类型参数T必须是MyClass或其子类,且实现Serializable接口
public class Container<T extends MyClass & Serializable> {
private T item;
// ...
}
需要注意的是,类型参数的约束最多只能有一个类(可以是抽象类),且必须位于extends子句的第一个位置,后面可以跟多个接口。
泛型类的继承与接口实现
泛型类也可以被继承,子类可以选择保留父类的类型参数,或者指定具体的类型。
// 父泛型类
class Parent<T> {
private T value;
}
// 子类保留父类的类型参数
class Child<T> extends Parent<T> {
// ...
}
// 子类指定父类的类型参数为String
class ChildString extends Parent<String> {
// ...
}
如果子类继承泛型父类时未指定类型参数,子类也需要声明为泛型类;如果指定了具体类型,则子类不再是泛型类。
泛型类可以实现泛型接口或非泛型接口。
// 泛型接口
interface Interface<T> {
void process(T t);
}
// 泛型类实现泛型接口
class MyClass<T> implements Interface<T> {
@Override
public void process(T t) {
System.out.println("Processing: " + t);
}
}
// 非泛型类实现泛型接口(指定具体类型)
class MyClassString implements Interface<String> {
@Override
public void process(String t) {
System.out.println("Processing: " + t);
}
}
通配符的使用
在处理泛型类时,有时需要编写能够适应多种类型参数的代码,这时可以使用通配符,通配符分为无界通配符、上界通配符和下界通配符三种。
-
无界通配符:表示未知类型,适用于不需要关心具体类型的场景。
public void printList(List<?> list) { for (Object obj : list) { System.out.println(obj); } }List<?>可以接受任何List类型(如List<String>、List<Integer>),但无法向list中添加除null外的任何元素,因为编译器无法确定的具体类型。 -
上界通配符
? extends T:表示类型参数是T或其子类,适用于读取数据的场景(生产者)。public double sum(List<? extends Number> list) { double sum = 0; for (Number num : list) { sum += num.doubleValue(); } return sum; }List<? extends Number>可以接受List<Integer>、List<Double>等,但无法向list中添加元素(因为无法确定具体类型是Number的哪个子类),可以安全地读取Number类型的数据。
-
下界通配符
? super T:表示类型参数是T或其父类,适用于写入数据的场景(消费者)。public void addNumbers(List<? super Integer> list) { list.add(10); // 可以添加Integer及其子类 list.add(20); }List<? super Integer>可以接受List<Integer>、List<Number>、List<Object>等,可以向list中添加Integer或其子类,但读取时只能作为Object类型处理。
泛型类的注意事项
-
类型擦除:Java的泛型是在编译阶段实现的,运行时泛型类型会被擦除为原始类型(Object或约束的类型)。
Box<String>和Box<Integer>在运行时都是Box类型,因此无法通过instanceof检查泛型类型(如box instanceof Box<String>会编译报错)。 -
不能创建泛型数组:由于类型擦除,无法直接创建泛型数组。
new T[]是非法的,但可以通过反射或强制转换为Object数组后再转换来实现,但需谨慎使用。 -
静态方法与类型参数:静态方法不能使用类定义的类型参数,如果静态方法需要使用泛型,必须单独声明自己的类型参数。
public class Util { public static <T> void swap(T[] array, int i, int j) { T temp = array[i]; array[i] = array[j]; array[j] = temp; } }
泛型类的定义是Java泛型机制的重要应用,通过类型参数实现了代码的类型安全性和复用性,在定义泛型类时,需要注意类型参数的声明、约束条件、继承与接口实现规则,以及通配符的合理使用,要理解类型擦除的本质,避免在运行时依赖泛型类型信息,掌握泛型类的定义和使用,能够编写更加健壮、灵活的Java代码,是提升编程能力的重要一步。
















