22. 泛型常用特点
大约 4 分钟
Java中的泛型提供了一种类型安全的机制,使得代码可以在处理不同类型的数据时避免类型转换错误,并且可以复用。以下是Java泛型的常用特点:
1. 类型参数
- 泛型类、泛型接口:定义类或接口时,可以使用类型参数来表示其将要处理的类型。常用的类型参数符号是
T
、E
、K
、V
等。 - 泛型方法:在方法中定义类型参数,使方法可以处理不同类型的数据。
// 泛型类
class Box<T> {
private T item;
public void setItem(T item) { this.item = item; }
public T getItem() { return item; }
}
// 泛型方法
public <T> void print(T item) {
System.out.println(item);
}
2. 类型安全
- 泛型允许在编译时检查类型错误,避免了运行时的
ClassCastException
,从而提高了程序的安全性。
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(10); // 编译错误,类型不匹配
3. 类型擦除
- Java泛型采用类型擦除(Type Erasure)机制,这意味着泛型类型在编译时会被擦除,编译后的字节码中不保留类型参数。类型擦除的结果是,泛型类或方法在运行时仍然处理
Object
类型。 - 这也是为什么在运行时不能获取泛型的具体类型,也不能创建泛型类型的实例(
new T()
是非法的)。
public class Box<T> {
// 编译错误:不能创建泛型类型的实例
// private T item = new T();
}
4. 泛型通配符
- 泛型通配符用于表示未知的类型,有三种常见形式:
- 无界通配符
<?>
:表示可以接受任何类型。例如:List<?>
。 - 上界通配符
<? extends T>
:表示可以接受T
或T
的子类型。例如:List<? extends Number>
可以接受List<Integer>
或List<Double>
。 - 下界通配符
<? super T>
:表示可以接受T
或T
的超类型。例如:List<? super Integer>
可以接受List<Number>
或List<Object>
。
- 无界通配符
public void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
public void addNumbers(List<? super Integer> list) {
list.add(10); // 可以添加Integer类型的元素
}
5. 泛型的限制
- 基本类型不能作为类型参数:泛型只能用于引用类型,不能直接使用基本类型,如
int
、char
等。但可以使用其包装类,如Integer
、Character
等。
List<int> list = new ArrayList<>(); // 编译错误
List<Integer> list = new ArrayList<>(); // 正确
- 泛型类的静态成员:泛型类中的静态成员不能使用类型参数,因为类型参数在类的实例化时才会确定,而静态成员属于类本身。
class Box<T> {
// static T item; // 编译错误
}
- 不能创建泛型数组:由于类型擦除机制,不能直接创建泛型类型的数组。
// T[] array = new T[10]; // 编译错误
6. 泛型与继承的关系
- 泛型类型之间没有继承关系,例如
List<String>
与List<Object>
没有继承关系,但可以使用通配符进行协变或逆变处理。 - 可以使用通配符(如
<? extends T>
)来处理继承关系。
List<Object> objList = new ArrayList<>();
List<String> strList = new ArrayList<>();
objList = strList; // 编译错误,没有继承关系
// 可以使用通配符
List<? extends Object> wildcardList = strList; // 正确
7. 泛型方法与类型推断
- 当调用泛型方法时,编译器会根据传递的参数自动推断类型参数,这被称为类型推断。
public static <T> void printItem(T item) {
System.out.println(item);
}
public static void main(String[] args) {
printItem("Hello"); // 类型推断为String
printItem(123); // 类型推断为Integer
}
8. 泛型的桥方法
- 在泛型类中,由于类型擦除的存在,编译器在编译时会生成桥方法(Bridge Method)以确保类型安全性和多态性,这些桥方法用于在运行时处理类型擦除后的类型转换。
总结
Java泛型的主要特点包括类型安全、类型擦除、通配符的使用、基本类型限制、泛型与继承的关系等。泛型使得代码更加灵活和复用,同时保证了类型的安全性。掌握这些特点有助于更好地使用泛型编写类型安全和高效的代码。