Java 泛型(Generics)是 Java 5 引入的一项重要特性,它允许你在编译时检查类型安全,并且所有的强制类型转换都是自动和隐式的,提高了代码的重用率。泛型可以应用于类、接口、方法和构造器等。
泛型的基本概念
- 类型参数:在定义泛型类、接口或方法时使用的占位符,通常用大写字母表示,如
T
、E
、K
、V
等。 - 类型实参:在使用泛型类、接口或方法时提供的具体类型,用于替换类型参数。
- 泛型类:带有类型参数的类。
- 泛型接口:带有类型参数的接口。
- 泛型方法:带有类型参数的方法。
- 泛型构造器:带有类型参数的构造器。
- 通配符:用于表示未知类型,主要有三种形式:
?
、? extends T
、? super T
。
泛型类
定义泛型类
public class Box<T> {
private T item;
public Box(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
使用泛型类
public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>("Hello");
System.out.println(stringBox.getItem()); // 输出: Hello
Box<Integer> integerBox = new Box<>(123);
System.out.println(integerBox.getItem()); // 输出: 123
}
}
泛型接口
定义泛型接口
public interface Container<T> {
void add(T item);
T get(int index);
}
实现泛型接口
public class ArrayListContainer<T> implements Container<T> {
private List<T> list = new ArrayList<>();
@Override
public void add(T item) {
list.add(item);
}
@Override
public T get(int index) {
return list.get(index);
}
}
使用泛型接口
public class Main {
public static void main(String[] args) {
Container<String> stringContainer = new ArrayListContainer<>();
stringContainer.add("Hello");
System.out.println(stringContainer.get(0)); // 输出: Hello
Container<Integer> integerContainer = new ArrayListContainer<>();
integerContainer.add(123);
System.out.println(integerContainer.get(0)); // 输出: 123
}
}
泛型方法
定义泛型方法
public class Util {
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.print(item + " ");
}
System.out.println();
}
}
使用泛型方法
public class Main {
public static void main(String[] args) {
String[] strings = {"Hello", "World"};
Util.printArray(strings); // 输出: Hello World
Integer[] integers = {1, 2, 3};
Util.printArray(integers); // 输出: 1 2 3
}
}
通配符
通配符 ?
表示未知类型,可以用于限制类型范围。
上界通配符 ? extends T
表示类型参数必须是 T
的子类型。
public class Main {
public static void printList(List<? extends Number> list) {
for (Number number : list) {
System.out.print(number + " ");
}
System.out.println();
}
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1, 2, 3);
printList(intList); // 输出: 1 2 3
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
printList(doubleList); // 输出: 1.1 2.2 3.3
}
}
下界通配符 ? super T
表示类型参数必须是 T
的父类型。
public class Main {
public static void addNumbers(List<? super Integer> list) {
list.add(1);
list.add(2);
}
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
addNumbers(intList);
System.out.println(intList); // 输出: [1, 2]
List<Number> numberList = new ArrayList<>();
addNumbers(numberList);
System.out.println(numberList); // 输出: [1, 2]
}
}
泛型的类型擦除
Java 泛型在运行时会被擦除,这意味着在运行时无法获取泛型的具体类型信息。例如,List<String>
和 List<Integer>
在运行时都表现为 List
。
示例
public class Main {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
System.out.println(stringList.getClass() == integerList.getClass()); // 输出: true
}
}
泛型方法的类型推断
Java 编译器可以自动推断泛型方法的类型参数,从而简化代码。
示例
public class Util {
public static <T> T first(T[] array) {
return array[0];
}
}
public class Main {
public static void main(String[] args) {
String[] strings = {"Hello", "World"};
String firstString = Util.first(strings); // 编译器自动推断 T 为 String
System.out.println(firstString); // 输出: Hello
Integer[] integers = {1, 2, 3};
Integer firstInteger = Util.first(integers); // 编译器自动推断 T 为 Integer
System.out.println(firstInteger); // 输出: 1
}
}
总结
Java 泛型是一项强大的特性,可以提高代码的类型安全性和重用率。通过泛型类、接口、方法和通配符,你可以编写更加灵活和安全的代码。希望这些示例和解释能帮助你更好地理解和使用 Java 泛型。