从示例代码看java泛型
仅从代码结果直接观察泛型特点,暂时还不太能特别讲明白为什么,以后如果真搞懂了,再来补全原理
/**
这里有一个Result类,用到了泛型
*/
@Builder
public class Result <T>{
private int code;
private String message;
private T data;
}
// 我们构造了一个result对象
Result result = Result.builder().data("/data/test").build();
// 等价于
Result<String> result1 = new Result();
// 也就是说此时result.getData()是一个String类型的
System.out.println(result.getData().getClass());
// 结果:class java.lang.String
// 此时我有一个方法,参数接受一个String类型
public static void test(String path){
System.out.println(path);
}
test(result.getData().toString()); //可行
test(result.getData()); //不可行,报错,required:String;provided:Object
// 问题1:为什么呢,我们打印result.getData().getClass()是String,为什么调用函数不可以
// 泛型擦除
在编译阶段,将所有的泛型标识都替换为具体的类型,即删除<>及其包围的部分。
替换原则:根据参数的上下界推断,如果类型参数是无限制通配符,则替换为Object,若有上界,则替换为其上界
ArrayList<Integer>,在类型擦除后,变为ArrayList<Object>,那么我们就可以通过反射添加String类型的数据
那么也就是说,在编译期,编译器无法识别data是String类型,认为其是一个Object类型
在运行期间,通过实例化,明确了其是String类型
// 代码示例2,这个和上面的不一样,此处编译器可以检查出错误
List<String> list = new ArrayList<>();
list.add("Hello"); // 编译通过
list.add(1); // 编译错误,提示类型不匹配
// 代码示例3
public class TypeErasureExample {
public static void main(String[] args) throws Exception {
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
// 使用反射获取 add 方法
Method addMethod = stringList.getClass().getMethod("add", Object.class);
// 使用反射添加一个 Integer 类型的元素
addMethod.invoke(stringList, 123);
// 打印集合内容
for (Object obj : stringList) {
System.out.println(obj);
}
}
}
输出:Hello 123
// 代码示例4
public class TypeErasureExample {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
// 添加一个 Integer 类型的元素
stringList.add((String) (Object) 123);
// 使用 instanceof 检查类型
for (Object obj : stringList) {
if (obj instanceof String) {
System.out.println("String: " + obj);
} else if (obj instanceof Integer) {
System.out.println("Integer: " + obj);
}
}
}
}
输出:String: Hello Integer: 123