面试题答案
一键面试类型擦除带来的问题
- 反射操作问题:
- 由于类型擦除,在反射中获取泛型参数实际类型会变得困难。例如,当通过反射调用方法时,泛型类型信息在运行时丢失,这可能导致参数类型不匹配错误。
- 代码示例:
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class ReflectionGenericProblem {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("test");
Class<?> listClass = list.getClass();
Method addMethod = listClass.getMethod("add", Object.class);
// 由于类型擦除,这里可以传入任何类型,可能导致运行时错误
addMethod.invoke(list, 123);
System.out.println(list.get(1));
}
}
- 继承体系下泛型类使用问题:
- 泛型类型擦除可能破坏继承体系下的类型安全性。例如,一个泛型类
GenericClass<T>
,如果在子类中使用了通配符,类型擦除后可能导致父类和子类之间的类型一致性出现问题。 - 代码示例:
- 泛型类型擦除可能破坏继承体系下的类型安全性。例如,一个泛型类
class GenericClass<T> {
private T value;
public GenericClass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
class SubGenericClass extends GenericClass<? extends Number> {
public SubGenericClass(Number value) {
super(value);
}
}
public class InheritanceGenericProblem {
public static void main(String[] args) {
SubGenericClass sub = new SubGenericClass(123);
// 由于类型擦除,这里编译通过,但运行时可能出现类型转换异常
Object result = sub.getValue();
Integer num = (Integer) result;
}
}
解决方法
- 反射操作解决方法:
- 可以通过在运行时传递额外的类型信息来解决反射中的泛型问题。例如,使用
TypeToken
类(Guava库提供,也可自己实现类似功能)。 - 代码示例:
- 可以通过在运行时传递额外的类型信息来解决反射中的泛型问题。例如,使用
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class ReflectionGenericSolution {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("test");
TypeToken<List<String>> typeToken = new TypeToken<List<String>>() {};
Class<?> listClass = typeToken.getRawType();
Method addMethod = listClass.getMethod("add", typeToken.getType().getTypeArguments()[0]);
addMethod.invoke(list, "newTest");
System.out.println(list.get(1));
}
}
- 继承体系下泛型类使用解决方法:
- 在子类定义时,尽量明确泛型类型,避免过多使用通配符导致类型擦除带来的不确定性。如果必须使用通配符,在方法调用中进行合适的类型检查。
- 代码示例:
class GenericClass<T> {
private T value;
public GenericClass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
class SubGenericClass extends GenericClass<Integer> {
public SubGenericClass(Integer value) {
super(value);
}
}
public class InheritanceGenericSolution {
public static void main(String[] args) {
SubGenericClass sub = new SubGenericClass(123);
Integer result = sub.getValue();
System.out.println(result);
}
}
通过以上方法,可以在一定程度上解决泛型通配符在复杂场景下由于类型擦除带来的问题,保证代码的类型安全性和可靠性。