面试题答案
一键面试类型擦除原理
在Java中,泛型主要是在编译期起作用,运行时会进行类型擦除。对于泛型类型参数,在编译后会被替换为其限定的上限(如果有),如果没有上限则替换为Object
。例如List<Integer>
在运行时实际类型是List
,Integer
类型信息被擦除。
确保代码类型安全性
List<? extends Number>
:- 这种通配符表示该
List
可以包含Number
及其子类的元素。由于类型擦除,运行时无法确切知道具体的元素类型,但编译器会在编译期进行类型检查。 - 例如,以下代码在编译期会报错:
- 这种通配符表示该
List<? extends Number> list1 = new ArrayList<>();
list1.add(new Integer(1)); // 编译错误,因为编译器不知道list1实际允许的具体类型
- 但是可以安全地读取元素,因为返回类型至少是
Number
:
List<? extends Number> list1 = new ArrayList<>();
Number num = list1.get(0);
List<? super Integer>
:- 此通配符表示该
List
可以包含Integer
及其超类的元素。同样由于类型擦除,运行时具体类型不确定,但编译期编译器会确保类型安全。 - 可以向
List
中添加Integer
及其子类元素:
- 此通配符表示该
List<? super Integer> list2 = new ArrayList<>();
list2.add(new Integer(1));
list2.add(new Double(2.0)); // 编译错误,因为Double不是Integer的子类
- 读取元素时,由于不知道具体的上限类型,只能用
Object
接收:
List<? super Integer> list2 = new ArrayList<>();
Object obj = list2.get(0);
可能出现的类型相关问题及解决方法
- 问题:
- 类型不匹配问题。例如,尝试将错误类型的元素添加到
List
中,如上面List<? extends Number>
中添加Integer
元素的情况。
- 类型不匹配问题。例如,尝试将错误类型的元素添加到
- 解决方法:
- 避免直接向
List<? extends Number>
中添加元素,如果需要添加元素,可以定义一个方法来处理,方法参数为具体的类型。例如:
- 避免直接向
List<Number> numbers = new ArrayList<>();
void addNumber(List<? super Number> list, Number num) {
list.add(num);
}
addNumber(numbers, new Integer(1));
- 对于读取
List<? super Integer>
的情况,如果需要特定类型的元素,可以在获取元素后进行类型检查和转换:
List<? super Integer> list2 = new ArrayList<>();
list2.add(new Integer(1));
Object obj = list2.get(0);
if (obj instanceof Integer) {
Integer intValue = (Integer) obj;
// 处理Integer值
}