在Java中,泛型是十分强大的功能,它允许我们在类、方法和接口中使用类型参数,提供安全且灵活的代码。反省通过让你指定通用类型参数来实现“类型独立性”,避免显式的类型转换(数据类型的强转肯定都用过),同时提高了代码的可读性和可维护性。
泛型类指的是在类定义时使用类型参数(比如
:泛型类型参数,表示任意类型。通常用于类、方法的单一类型参数。
:泛型元素类型参数,通常用于表示集合类中元素的类型,如
List
、Set
等。:泛型键值对类型参数,常用于表示映射类(如
Map
)的键值对类型。注:这些字母只是符号,代表不同的泛型类型参数,命名可以根据需求进行调整,其他字母也可以使用,其本质上就是一个占位符而已,没有特定的功能,但 Java 的社区约定了这些字母的使用方式,帮助代码更具可读性和一致性,最好还是遵守这些默认的编程规范。
public class Box {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
===========================使用示例======================
Box intBox = new Box<>();
intBox.set(10); // T 被替换为 Integer 类型
Integer value = intBox.get(); // 返回类型为 Integer
T
被替换为具体的类型(如 Integer
或 String
)。泛型方法是指方法本身使用泛型,允许方法在调用时指定类型。它与泛型类不同,泛型参数只作用于该方法。
public class Util {
public static void printArray(T[] array) { // 表示这是一个泛型方法
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
}
public static
表示定义一个泛型方法,并且 T
只在该方法的作用域内有效。T[] array
表明它可以接受任何类型的数组作为参数。使用
Integer[] intArray = {1, 2, 3};
String[] strArray = {"apple", "banana", "cherry"};
Util.printArray(intArray); // 输出 1 2 3
Util.printArray(strArray); // 输出 apple banana cherry
声明泛型参数后,调用该方法时可以传入不同类型的参数。通配符是 Java 泛型中用于表示未知类型的符号。常见的通配符有三种类型:
?
:表示未知类型。? extends T
:表示一个类型为 T
或其子类型的类型。? super T
:表示一个类型为 T
或其父类型的类型。?是最基本的通配符,表示任何类型。通常用于不关系具体类型的情况下。
List> list = new ArrayList(); // 可以是任何类型的 List
? extends T
表示类型为 T
或 T
的子类。这个通配符通常用于读取数据,因为它允许你读取 T
或 T
的子类的元素。
public static void printList(List extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
List intList = new ArrayList<>();
intList.add(1);
intList.add(2);
printList(intList); // 适用于 List
? extends T
允许传入 T
或 T
的任何子类(包括 Integer
、Double
等)。T
或 T
的任何子类,但不能向集合中添加元素(除了 null
)。? super T
表示类型为 T
或 T
的父类。这个通配符通常用于向集合中添加数据,因为它允许你添加 T
或 T
的子类的元素。
public static void addNumbers(List super Integer> list) {
list.add(10); // 可以安全地添加 Integer 或其子类
}
List numberList = new ArrayList<>();
addNumbers(numberList); // 可以传入 List 或 List
? super T
允许传入 T
或 T
的任何父类(包括 Object
)。T
类型或其子类的对象。通配符 | 含义 | 用法 |
---|---|---|
? |
表示任何类型 | 用于不关心类型时(例如:List> ) |
? extends T |
表示 T 或 T 的子类 |
用于读取数据(例如:List extends Number> ) |
? super T |
表示 T 或 T 的父类 |
用于向集合中添加数据(例如:List super Integer> ) |
?
用于无法确定具体类型时,例如在某些方法中只需要通用类型参数时。? extends T
用于方法参数中,当你只需要读取集合中的元素,且知道它们是 T
或 T
的子类时。? super T
用于方法参数中,当你需要向集合中添加元素,且知道它们是 T
或 T
的父类时。尽管泛型在 Java 中非常强大,但它也有一些限制:
不能使用基本数据类型:Java 的泛型只能使用对象类型,不能直接使用基本数据类型,如 int
、char
等。你可以使用包装类,如 Integer
、Character
等。
不能创建泛型数组:由于泛型类型在运行时会被擦除,所以你不能创建泛型数组。
// 错误,不能创建泛型数组
// T[] array = new T[10];
// 正确,使用 Object 数组
Object[] array = new Object[10];
类型擦除:Java 泛型使用类型擦除(Type Erasure)机制,在运行时泛型类型信息被擦除,只保留原始类型。因此,你不能通过反射获取泛型的实际类型。
public class Box {
// 在运行时 T 会被擦除成 Object
}
注:Java 泛型中,?
(通配符)和字母(如 T
、E
、K
、V
等)的泛型类型参数的确都能够表示某种类型,但它们的使用场景和目的有很大的区别。简而言之,字母泛型通常是在定义类、方法或者接口时用于表示某个类型,而通配符 ?
则是在使用这些类、方法时表示任意类型,并且具有更强的灵活性。
?
:用于方法参数中,表示一个未知类型。在方法内部,?
提供了更灵活的类型接受能力,同时通过 ? extends T
和 ? super T
可以限定操作范围(如只允许读取、只允许写入)。