5个Java泛型面试问题(附详细答案)
Java泛型是许多Java开发者面试中的一个关键话题。掌握这些概念可以帮助你在编写复杂Java代码时确保类型安全。以下是五个重要的Java泛型面试问题,并附有详细答案。
1. List<?>、List和List<? extends Object>之间有什么区别?
回答:
**List<?>:** 代表可以包含任何类型元素的列表。但由于类型未知,除了null之外,不能添加任何元素。 **List:** 这是一个可以包含任何类型元素的列表,但它们应该是Object类型或其子类。你可以自由添加任何分配给Object的元素。 **List<? extends Object>:** 这是一个可以包含任何Object子类类型元素的列表。它类似于List<?>,但明确表示了Object的上界。
实际应用中:
List<?> unknownList; // 你不能添加元素,只能读取。
List<Object> objectList; // 你可以添加任何对象。
List<? extends Object> boundedList; // 你可以读取但不能写入。
2. Java泛型中的协变与逆变有什么区别?
回答:
协变(? extends T): 允许泛型类型成为特定类型T的子类型。通常在你想从结构中读取而不修改时使用。
示例:
List<? extends Number> numberList;
// 你可以将List<Integer>、List<Double>分配给numberList。
逆变(? super T): 允许泛型类型成为特定类型T的超类型。当你想写入结构时使用。
示例:
List<? super Integer> integerList;
// 你可以将List<Integer>、List<Number>或List<Object>分配给integerList。
用法:
- 当你需要读取数据时使用协变(? extends T)。
- 当你需要写入数据时使用逆变(? super T)。
3. 能否将List传递给接受List的方法?
回答:
不能,因为Java泛型是不变的。这意味着List和List被视为完全不同的类型,不兼容。
解决方法:
你可以使用通配符进行只读操作:
public void method(List<?> list) {
// 这对List<String>、List<Integer>等都有效。
}
如果需要修改列表,你也可以将List复制到一个新的List中。
这种限制确保了Java中的类型安全。
4. 什么是类型擦除?
回答:
类型擦除是Java编译器在编译阶段之后移除所有泛型类型信息的过程。
关键点:
-
在编译时,编译器强制执行类型检查并确保类型安全。
-
在运行时,类型信息被擦除,这意味着像List和List这样的泛型类型都会变成普通的List。
例如,一个方法:public void method(List<String> list) { }
在类型擦除后,会变成:
public void method(List list) { }
这就是为什么在不同泛型类型上进行方法重载受到限制的原因。
5. 能否重载方法以处理List和List?
回答:
不能,因为类型擦除会移除运行时的泛型信息。
例如:
public void method(List<Integer> list) { }
public void method(List<Double> list) { }
这两种方法会被擦除成:
public void method(List list) { }
这会导致编译时错误,因为方法签名冲突。在擦除之后,签名是相同的。
这五个问题涵盖了一些关于Java泛型的重要方面,深入理解这些概念可以大大提升你的Java问题解决能力。好好准备,你就能应对最严峻的面试挑战!