泛型(Generics)
Java中的泛型(Generics)是JDK 5引入的一种特性,它使得类、接口和方法能够以一种类型参数化的方式进行定义和使用。泛型的主要目的是增强代码的类型安全性和可读性,同时减少类型转换(cast)操作。
泛型的基本概念
泛型允许我们在类、接口和方法中定义和使用参数化类型,即用一个占位符(类型参数)来表示实际类型。在实际使用时,具体类型会替换这些类型参数。
泛型类
定义一个带有类型参数的类:
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
使用泛型类时指定具体类型:
public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();
System.out.println(content); // 输出: Hello
Box<Integer> intBox = new Box<>();
intBox.setContent(123);
int number = intBox.getContent();
System.out.println(number); // 输出: 123
}
}
泛型接口
定义一个带有类型参数的接口:
public interface Container<T> {
void add(T item);
T get(int index);
}
实现泛型接口时指定具体类型:
public class StringContainer implements Container<String> {
private List<String> items = new ArrayList<>();
@Override
public void add(String item) {
items.add(item);
}
@Override
public String get(int index) {
return items.get(index);
}
}
泛型方法
定义一个带有类型参数的方法:
public class Util {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
使用泛型方法:
public class Main {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4};
String[] stringArray = {"Hello", "World"};
Util.printArray(intArray); // 输出: 1 2 3 4
Util.printArray(stringArray); // 输出: Hello World
}
}
泛型的高级特性
通配符
Java泛型中的通配符用于表示不确定的类型,可以用在类和方法的参数中。
- 无界通配符 (
<?>
):
用于表示任意类型。
public static void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
- 有界通配符(上界) (
<? extends T>
):
用于表示某个类型的子类型。
public static void printNumbers(List<? extends Number> list) {
for (Number number : list) {
System.out.println(number);
}
}
- 有界通配符(下界) (
<? super T>
):
用于表示某个类型的父类型。
public static void addNumber(List<? super Integer> list) {
list.add(1); // 允许添加Integer或其子类类型的对象
}
泛型类型擦除
在Java中,泛型是在编译时处理的,编译后所有的泛型信息都会被擦除,这个过程被称为类型擦除(Type Erasure)。类型擦除会将泛型类型替换为其限定类型(通常是Object),并插入类型转换以保持类型安全。
例如,以下泛型类:
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
在编译后,大致会变成:
public class Box {
private Object content;
public void setContent(Object content) {
this.content = content;
}
public Object getContent() {
return content;
}
}
泛型的限制
由于类型擦除的存在,泛型在Java中有一些限制:
- 不能使用基本类型:泛型类型参数不能是基本类型(如
int
、char
等),只能使用包装类型(如Integer
、Character
等)。 - 运行时类型查询:在运行时,无法获得泛型类型参数的信息,因此不能使用
instanceof
和getClass
来检查泛型类型。 - 静态上下文中不能使用泛型类型参数:泛型类型参数不能用于静态变量、静态方法或静态代码块中。
- 不能创建泛型数组:例如
new T[10]
是不允许的,因为在运行时无法确定类型T
。
泛型的使用场景
泛型广泛应用于集合框架(如List<T>
、Map<K, V>
等),使得代码更加类型安全,并提高了代码的重用性和可读性。
通过了解和使用Java中的泛型,可以编写更为灵活、安全和可维护的代码。