Java泛型
Java泛型
- Java中的泛型(Generics)是一种通过参数化类型来增强代码重用性和类型安全性的机制。它使得类、接口和方法能够操作不同类型的数据,而无需在编译时指定具体的类型。
1. 泛型的基本概念
- 泛型允许在编写类、接口和方法时,不确定它们将操作的对新的类型,而是在实例化时指定具体的类型参数。类似于通配符。
2. 泛型的作用
- 类型安全: 使用泛型可以在编译时检查类型,减少运行时错误。
- 代码复用: 泛型允许编写通用的代码,可以处理不同类型的数据。
- 避免强制类型转换: 使用泛型可以避免在使用对象时进行强制类型转换,提高代码的可读性和安全性。
3. 泛型的基本语法
- 泛型通常通过尖括号
<>来指定,<>是占位符,用来表示类型:- 泛型类:
class ClassName<T>,其中T代表一种类型。 - 泛型方法:
<T> void method(T param),其中<T>表示传入方法的类型。
- 泛型类:
4. 泛型的使用示例
-
假设一个容器类(比如Box),它可以存储任何类型的对象。如果没有泛型,我们就只能存储特定类型的对象,且取出时需要做类型转换。使用泛型后,容器可以存储任何类型的对象,同时避免了类型转换的问题。
-
没有泛型的容器类示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Box {
private Object value;
public void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
public static void main(String[] args) {
Box box = new Box();
box.setValue("Hello");
String message = (String) box.getValue(); // 强制类型转换
System.out.println(message);
}
} -
使用泛型的容器类示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Box<T> { // 使用泛型 T
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public static void main(String[] args) {
Box<String> box = new Box<>(); // 创建一个存储 String 类型的 Box
box.setValue("Hello");
String message = box.getValue(); // 不需要强制类型转换
System.out.println(message);
}
}
5. 泛型方法
-
泛型方法允许在方法级别上使用泛型类型参数。可以在方法声明中指定类型参数,并在方法体内使用它们。
-
泛型方法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class GenericMethodExample {
// 泛型方法
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
String[] strArray = {"Hello", "World"};
printArray(intArray); // 调用泛型方法,传入 Integer 数组
printArray(strArray); // 调用泛型方法,传入 String 数组
}
}这里的
<T>表示该方法是一个泛型方法,可以接收任何类型的数组作为参数。无论是Integer类型的数组,还是String类型的数组,都可以通过这个方法进行打印。
6. 泛型的边界(Bounded Type Parameters)
-
泛型类型参数可以加边界(Bound),限制其可以接受的范围。使用
extends关键字,你可以指定泛型的上边界,这样泛型参数就只能是指定类或其子类的类型。 -
泛型边界示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class BoundedTypeExample {
public static <T extends Number> void printNumbers(T[] numbers) {
for (T num : numbers) {
System.out.println(num);
}
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3};
Double[] doubleArray = {1.1, 2.2, 3.3};
printNumbers(intArray); // 适用于 Integer 类型
printNumbers(doubleArray); // 适用于 Double 类型
}
}<T extends Number>表示T只能是Number类或它的子类(如Integer、Double等)。这确保了T的类型是数字类型。
7. 通配符(Wildcards)
-
通配符
?用于表示未知类型。它可以用在泛型类、接口和方法中,以提高灵活性。常见的通配符:? extends T:表示类型是T或T的子类。? super T:表示类型是T或T的父类。
-
通配符示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class WildcardExample {
public static void printList(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
List<Double> doubleList = List.of(1.1, 2.2, 3.3);
printList(intList); // 适用于 Integer 类型
printList(doubleList); // 适用于 Double 类型
}
}这里的
List<? extends Number>表示可以接受任何Number及其子类的List(如Integer、Double等)。
8. 泛型的类型擦除
- Java中的泛型在编译时会进行类型擦除(Type Erasure),这意味着在编译后,所有的泛型类型信息都会被移除,替换为它们的上边界类型(如果没有指定上边界,则替换为Object)。这使得泛型在运行时不会引入额外的开销,但也带来了一些限制,比如不能使用基本数据类型作为泛型参数。
9. 总结
- 泛型的作用:
- 提供类型安全的代码。
- 增强代码的可重用性。
- 避免强制类型转换和运行时错误。
- 泛型语法:
- 泛型类:
class ClassName<T>。 - 泛型方法:
<T> void method(T param)。 - 边界(Bounded Type):
<T extends Number>。
- 泛型类:
- 通配符:
? extends T表示类型是T的子类? super T表示类型是T的父类。
