Java泛型高级使用
引言
Java泛型是Java SE 5引入的一个重要特性,它使得我们能够在编译时期对代码进行类型检查,从而提高代码的可读性和安全性。在初学者掌握了基本的泛型语法后,我们可以深入研究更高级的泛型技术,以应对更复杂的场景。本文将介绍一些Java泛型的高级使用,包括泛型通配符、泛型上下边界、泛型方法和泛型类的继承等。
泛型通配符
当我们使用泛型时,有时候会遇到无法确定泛型类型的情况,这时就可以使用泛型通配符。泛型通配符用?
表示,它可以匹配任何类型。下面是一个使用泛型通配符的示例:
List<?> list = new ArrayList<>();
list.add("Hello"); // 编译错误
list.add(123); // 编译错误
list.add(null); // 可以添加null
在上面的示例中,List<?>
表示这个List可以存放任何类型的元素。由于我们无法确定具体的类型,所以无法调用add
方法添加元素,只能添加null
。
泛型通配符还可以用于方法的参数类型和返回类型上。例如,我们有一个打印List元素的方法:
public static void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
在这个方法中,List<?>
表示这个方法可以接受任何类型的List作为参数。通过使用泛型通配符,我们可以实现更灵活的方法定义。
泛型上下边界
泛型上下边界可以限制泛型的类型范围。通常情况下,泛型可以是任意类型,但是有时候我们希望泛型只能是某个特定类型的子类或者父类。我们可以使用泛型上下边界来实现这个限制。下面是一个使用泛型上下边界的示例:
public static <T extends Number> void printNumber(T number) {
System.out.println(number);
}
public static void main(String[] args) {
printNumber(123); // 正常调用
printNumber(3.14); // 正常调用
printNumber("Hello"); // 编译错误
}
在上面的示例中,<T extends Number>
表示泛型T必须是Number类或其子类。通过使用泛型上边界,我们可以限制泛型只能是特定类型的子类。
泛型下边界与泛型上边界相反,它可以限制泛型必须是某个特定类型的父类。下面是一个使用泛型下边界的示例:
public static <T super Integer> void printInteger(T number) {
System.out.println(number);
}
public static void main(String[] args) {
printInteger(123); // 正常调用
printInteger(3.14); // 编译错误
printInteger("Hello"); // 编译错误
}
在上面的示例中,<T super Integer>
表示泛型T必须是Integer类或其父类。通过使用泛型下边界,我们可以限制泛型只能是特定类型的父类。
泛型方法
泛型方法是一种在方法中使用泛型的技术,它可以使得方法的参数和返回类型具备更大的灵活性。下面是一个使用泛型方法的示例:
public static <T> T getFirstElement(List<T> list) {
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
strings.add("Java");
strings.add("Python");
String first = getFirstElement(strings);
System.out.println(first); // 输出:Java
List<Integer> numbers = new ArrayList<>();
numbers.add(123);
numbers.add(456);
Integer firstNumber = getFirstElement(numbers);
System.out.println(first