Java核心 - 泛型
Java核心 - 泛型
什么是泛型?
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的核心就是参数化类型,通过参数将类型传递进来,也就是说所操作的数据类型被指定为一个参数。即就是在泛型的使用过程中,操作的数据类型被指定为一个参数,这种参数可以使用在 接口、类、方法上,称为 泛型接口、泛型类、泛型方法。
JDK 为了兼容以前的版本,Java 泛型的实现采用的是“伪泛型”,即在语法上支持泛型,但是在编译时会进行“泛型擦除”,将所有的泛型修改为传入的具体类型。
为什么要用泛型?
在说明为什么使用泛型之前,我们先看一个简单的例子:
假如现在要写一个 排序方法,要求这个排序方法能够排序 int、long、float,甚至是 String 类型的数组,应该怎么做。
通过前面了解的知识,可以实现这个功能的只有方法的重载,通过不同的参数列表来匹配不同的类型。
public class MethodOverLoading {
public void sort(int[] arr){
Arrays.sort(arr);
}
public void sort(float[] arr){
Arrays.sort(arr);
}
public void sort(long[] arr){
Arrays.sort(arr);
}
public void sort(double[] arr){
Arrays.sort(arr);
}
public void sort(String[] arr){
Arrays.sort(arr);
}
}
这样做的后果就是不同的排序算法中出现了大量重复的逻辑,仅有数据类型不同,但是实际的处理逻辑都是相同的,此时我们可以使用泛型来更简单的实现。
public class Generics<T> {
public void sort(T[] arr) {
Arrays.sort(arr);
}
}
相比之下,泛型类更加的简单,而且更易维护。
总的来说适用泛型的情况就是:多种数据类型执行相同的代码(代码复用)
泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
泛型的使用
泛型类相关的标识符
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ?- 表示不确定的 Java 类型
泛型上下限
在使用泛型的时候,我们可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类。
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
<? extends E> extends // 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类
<? super E> super // 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类
泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。泛型类的类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
class Student <T> {
T name;
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
}
泛型接口
public interface Person<T> {
T getName();
void set(T name);
}
泛型方法
定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 <E>),来说明该方法中使用到了 <E> 泛型类。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)
- 如果该泛型方法是泛型类中的,那么可以在任意位置使用泛型类。
- 如果泛型方法仅在该方法内使用泛型,那么仅能在该方法中使用。
泛型方法测试类:
public class GenericsMethodTest {
public static <E> void printArray(E[] arr) {
// 输出数组元素
for (E element : arr) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
如何使用泛型类来创建泛型对象?
这里可以使用反射,先获取该泛型类的 class 对象,在获取 构造器,通过构造器来实例化对象。
反射可参考该文:https://www.codermast.com/java/basis/reflection.html