Java泛型允许在定义类、接口和方法时使用类型参数,让代码可以适配多种数据类型,同时保证编译期的类型安全。泛型中的T、E等占位符本质上是类型参数的标识,用来指代后续传入的具体类型。

泛型类的定义与T占位符用法
泛型类是在类定义时声明类型参数的类,最常见的类型参数占位符是T,代表Type(类型)。定义泛型类时,需要在类名后添加<类型参数>的声明,之后在类中就可以使用该类型参数作为成员属性、方法参数或返回值的类型。
下面是一个简单的泛型类示例,使用T作为占位符:
// 定义泛型类,T是类型参数占位符
public class GenericClass<T> {
// 使用T作为成员属性的类型
private T data;
// 使用T作为方法参数的类型
public void setData(T data) {
this.data = data;
}
// 使用T作为方法返回值的类型
public T getData() {
return data;
}
public static void main(String[] args) {
// 创建泛型类实例时指定T为String类型
GenericClass<String> stringGeneric = new GenericClass<>();
stringGeneric.setData("泛型测试");
String str = stringGeneric.getData();
System.out.println(str);
// 创建泛型类实例时指定T为Integer类型
GenericClass<Integer> integerGeneric = new GenericClass<>();
integerGeneric.setData(100);
Integer num = integerGeneric.getData();
System.out.println(num);
}
}
上述代码中,GenericClass后面的<T>声明了类型参数,实例化时传入String或Integer,T就会被替换为对应的类型,编译器会自动检查类型匹配,避免错误的类型赋值。
E占位符的常见使用场景
E是Element(元素)的缩写,通常用在集合相关的泛型定义中,代表集合中的元素类型。和T一样,E也是类型参数的占位符,只是命名习惯上的区别,用来更清晰地表达参数的含义。
下面是一个使用E作为占位符的泛型类示例,模拟简单的集合容器:
// 使用E作为占位符,代表集合中的元素类型
public class SimpleContainer<E> {
private E[] elements;
private int size;
public SimpleContainer(int capacity) {
// 泛型数组创建需要强制转换
this.elements = (E[]) new Object[capacity];
this.size = 0;
}
// 添加元素,参数类型为E
public void add(E element) {
if (size < elements.length) {
elements[size] = element;
size++;
}
}
// 获取元素,返回值类型为E
public E get(int index) {
if (index >= 0 && index < size) {
return elements[index];
}
return null;
}
public static void main(String[] args) {
// 指定E为String类型,容器只能存储String元素
SimpleContainer<String> stringContainer = new SimpleContainer<>(3);
stringContainer.add("第一个元素");
stringContainer.add("第二个元素");
System.out.println(stringContainer.get(0));
// 指定E为Integer类型,容器只能存储Integer元素
SimpleContainer<Integer> intContainer = new SimpleContainer<>(3);
intContainer.add(1);
intContainer.add(2);
System.out.println(intContainer.get(1));
}
}
泛型方法的定义
泛型方法是指声明了类型参数的方法,泛型方法可以定义在普通类中,也可以定义在泛型类中。定义泛型方法时,需要在方法的返回值前添加<类型参数>的声明。
下面是一个普通类中的泛型方法示例:
public class GenericMethodDemo {
// 泛型方法,<T>在返回值前声明,T是类型参数
public static <T> T getMiddleValue(T a, T b, T c) {
// 简单逻辑返回第二个参数作为示例
return b;
}
public static void main(String[] args) {
// 调用泛型方法,编译器自动推断T为String类型
String middleStr = getMiddleValue("A", "B", "C");
System.out.println(middleStr);
// 调用泛型方法,编译器自动推断T为Integer类型
Integer middleInt = getMiddleValue(1, 2, 3);
System.out.println(middleInt);
}
}
如果泛型方法定义在泛型类中,还可以使用类声明的类型参数,也可以额外声明自己的类型参数:
// 泛型类,声明了类型参数T
public class GenericClass<T> {
// 使用类的类型参数T的方法
public void printData(T data) {
System.out.println(data);
}
// 泛型方法,额外声明了自己的类型参数E
public <E> void printTwoData(T data1, E data2) {
System.out.println("第一个数据:" + data1);
System.out.println("第二个数据:" + data2);
}
public static void main(String[] args) {
GenericClass<String> demo = new GenericClass<>();
// 使用类的T参数,T为String
demo.printData("类的泛型参数");
// 泛型方法自己的E参数,自动推断为Integer
demo.printTwoData("混合参数", 123);
}
}
占位符的命名规范
除了T和E之外,Java泛型还有一些常见的占位符命名习惯:
- T:代表Type(类型),是最通用的占位符,可用于任何泛型场景
- E:代表Element(元素),多用于集合相关的泛型定义
- K:代表Key(键),多用于键值对结构的泛型,比如Map相关定义
- V:代表Value(值),和K配合使用,代表键值对中的值
- ?:代表通配符,用于表示未知的类型,和T、E等确定类型的占位符有区别
这些命名只是约定俗成的规范,并不是语法强制要求,开发者也可以自定义其他合法的标识符作为类型参数占位符,但遵循规范能让代码更易读。
注意事项
使用泛型时需要注意几个常见问题:
- 泛型类型参数不能是基本数据类型,比如不能使用<int>,必须使用对应的包装类<Integer>
- 泛型信息只在编译期存在,运行时会被擦除,因此不能通过new T()的方式创建泛型实例
- 静态方法不能使用类的泛型参数,如果静态方法需要使用泛型,必须定义为泛型方法,自己声明类型参数
泛型的核心价值是让代码更通用,同时减少强制类型转换的错误,掌握T、E等占位符的用法是熟练使用Java泛型的基础。