Java中的泛型(Generics)是JDK 5中引入的一个新特性,它提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型的好处
-
类型安全:泛型的主要目标是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在编译时强制实施这些限制。如果没有泛型,程序仍然可以编译和运行,但可能会遇到
ClassCastException
。 -
消除类型转换:使用泛型后,代码中的一些类型转换会自动处理,使得代码更加简洁,也减少了运行时错误的可能性。
-
泛型算法:通过泛型,可以编写能够独立于任何特定类型的算法。
泛型的使用
泛型类
泛型类是在类名后面添加了<类型>
的类。例如,Box
类可以定义为泛型类Box<T>
,T
(type的缩写)是一个类型占位符,表示一种未知的类型。使用泛型类时,需要指定这个类型参数的值,如Box<Integer>
或Box<String>
。
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
泛型接口
泛型接口与泛型类的定义及使用方式基本相同。泛型接口常被用在各种类的生产器中,可以看做一个模板。
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
泛型方法
泛型方法被定义在其返回类型前面的尖括号(<
和>
)中声明了一个或多个类型参数。泛型方法可以定义在泛型类中,也可以定义在非泛型类中。
public class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
类型通配符和边界
泛型代码中的?
被称为通配符(Wildcard),表示未知类型。通配符的使用场景主要是泛型作为方法参数时,定义方法能够接受泛型类型或泛型类型的子类作为参数。
? extends T
:表示该通配符所代表的类型是T类型的子类(或T本身),即上界通配符。? super T
:表示该通配符所代表的类型是T类型的父类(或T本身),即下界通配符。
擦除和转换
泛型是通过类型擦除来实现的,这意味着泛型信息只在编译阶段有效,在编译后的字节码中,泛型类型会被其限定类型(无界定的变量用Object)替换。例如,Box<Integer>
在运行时会被擦除成Box
。但需要注意的是,擦除是泛型的实现方式,而不是泛型的本质。
总之,泛型是Java语言的一个重要特性,它提供了编译时类型安全检测机制,消除了许多类型转换,使代码更加简洁和安全。泛型的使用涵盖了类、接口和方法,为Java程序提供了一种高效且类型安全的方式来处理不同类型的数据。