Java 泛型详解:概念、用法和注意事项
1. Java 泛型
在Java编程中,泛型是一项非常重要的特性。它允许我们编写能够处理不同类型数据的代码,提高代码的重用性和类型安全性。本文将详细介绍Java泛型的概念、用法和注意事项。
1.1 什么是泛型?
泛型是Java中一种参数化类型的概念。通过使用泛型,我们可以定义类、接口和方法,使其能够处理不同类型的数据,而不需要针对每种类型编写重复的代码。泛型在编译时会进行类型检查,从而提供更好的类型安全性。
1.2 泛型的基本用法
在Java中,泛型使用尖括号<>
来标识泛型类型。我们可以将泛型应用于类、接口和方法。
1.2.1 泛型类
泛型类是指具有一个或多个类型参数的类。通过在类名后面使用尖括号和类型参数,我们可以实现让类可以处理不同类型的数据。
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
上面的代码定义了一个Box
类,它有一个类型参数T
。可以通过调用setValue
和getValue
方法来设置和获取值。使用时,我们可以指定具体的类型:
Box<Integer> intBox = new Box<>();
intBox.setValue(1);
int value = intBox.getValue(); // value的类型为Integer
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
String str = stringBox.getValue(); // str的类型为String
这样,Box
类可以处理不同类型的数据,同时保持类型安全。
1.2.2 泛型接口
泛型接口与泛型类类似,也可以定义一个或多个类型参数的接口。使用方式与泛型类相同。 比如下列我们常用的List
public interface List<T> {
void add(T item);
T get(int index);
}
上面的代码定义了一个泛型接口List
,它有一个类型参数T
。具体实现类可以指定具体的类型。
1.2.3 泛型方法
泛型方法是指在方法声明中使用泛型类型的方法。可以将泛型方法定义在普通类中,也可以定义在泛型类中。
public class Utility {
public static <T> T getValue(T[] array, int index) {
return array[index];
}
}
上面的代码定义了一个静态泛型方法getValue
,用于获取数组中指定索引位置的元素。可以在调用时指定具体的类型。
Integer[] intArray = {1, 2, 3};
int value = Utility.<Integer>getValue(intArray, 1); // value的类型为Integer
String[] strArray = {"Hello", "World"};
String str = Utility.getValue(strArray, 0); // str的类型为String
1.2.4 通配符
通配符是泛型中的一种特殊语法,用于表示未知类型。在某些情况下,我们并不关心泛型的具体类型,而只关心它们之间是否相同或具有某些限制。
public void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
public void addAll(List<? extends Number> list, List<? super Integer> dest) {
for (Number item : list) {
dest.add((Integer) item);
}
}
上面的代码中,使用了?
通配符来表示未知类型。printList
方法可以接受任何类型的List
作为参数。addAll
方法接受一个限定了上界为Number
的List
和一个限定了下界为Integer
的List
作为参数。
1.3 泛型的注意事项
在使用泛型时,我们需要注意以下几点:
1.3.1 类型擦除
Java的泛型在编译时会进行类型擦除,即泛型的具体类型在运行时并不可见。这是为了保持与之前的版本的兼容性。因此,在泛型中不能使用与具体类型相关的操作,如new T()
和instanceof T
。
1.3.2 泛型数组
不能创建具有泛型类型的数组,但可以创建泛型类型的数组引用。
Box<Integer>[] intBoxes = new Box<Integer>[10]; // 编译错误
Box<Integer>[] intBoxes = new Box[10]; // 正确
1.3.3 类型推断
在使用泛型时,编译器会自动推断类型,省略类型参数的写法。
Box<Integer> intBox = new Box<>(); // 省略了类型参数
1.3.4 限定类型
泛型可以通过限定类型来控制输入的类型范围。例如,<? extends Number>
表示泛型类型必须是Number
类或其子类。
public void printNumbers(List<? extends Number> list) {
for (Number item : list) {
System.out.println(item);
}
}
1.4 总结
我们刚学的、常用的List,Set,Map等集合接口都是支持泛型的。
Java泛型是一项强大的特性,它提供了一种通用的方式来处理不同类型的数据。通过使用泛型,我们可以提高代码的重用性和类型安全性。在实际编程中,我们要注意泛型的基本用法和注意事项,以充分发挥其优势。