问题的起因是在我使用 Spring 的BeanUtils.copyProperties
方法时发现两个 POJO 如果拥有相同的字段名,即使泛型类型不同,值也会被拷贝过去。例如类 A 有一个类型为List<Integer>
的字段 integerList,类 B 有一个类型为List<String>
的字段也叫 integerList,那么使用 BeanUtils.copyProperties(b, a)时,integerList 字段会被拷贝过去。这时我想起了 Java 的类型擦除问题。我想问:
public class InvokeDTO {
private List<Integer> integerList;
public List<Integer> getIntegerList() {
return integerList;
}
public void setIntegerList(List<Integer> integerList) {
this.integerList = integerList;
}
}
public static void main(String[] args) {
InvokeDTO invokeDTO = new InvokeDTO();
Method[] methods = invokeDTO.getClass().getMethods();
for (Method method : methods) {
try {
if (method.getName().equals("setIntegerList")) {
method.invoke(invokeDTO, Lists.newArrayList("string0", "string1"));
}
} catch (Exception e) {}
}
System.out.println(invokeDTO.getIntegerList());
}
1
octobersnow 2019-12-20 14:08:01 +08:00 via iPhone
我记得类型擦出的确在编译阶段,但是字节码中貌似还是有相关的信息。
|
2
IMCA1024 2019-12-20 14:08:31 +08:00
点进去源码不是可以看了吗
|
3
cheng6563 2019-12-20 15:02:49 +08:00 via Android
局部变量里的泛型运行时没有任何作用。其他地方的泛型可以从反射 API 里读到,可以人工判断,但就算不判断也能塞不同的类型进去。
|
4
iffi 2019-12-20 15:57:07 +08:00 1
擦除是防止编译期间 不匹配的数据能写入。Class 记录了泛型类型。运行时是能获取泛型信息的。
|
5
palmers 2019-12-20 16:01:40 +08:00 2
泛型擦除的结论是没有问题的, 只不过现在 class 文件确实记录了泛型信息 - Signature Attribute,所以 javap 等反编译工具很多都可以解析到泛型信息, 但是这个泛型信息并不是给 jvm 用的, 具体规范这里有详细的描述:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html |
6
palmers 2019-12-20 16:07:46 +08:00
|
7
kilen3a 2019-12-20 16:21:50 +08:00 1
字节码的泛型是反射和 debug 时用的(获取当然也只能通过反射),泛型擦除在编译器发生这个说法没问题,而且运行时 JVM 不会使用到 class 常量池中的泛型
|
8
kilen3a 2019-12-20 16:26:21 +08:00
除了 4.7.9 外 4.3 ( https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3 )中也有说明
|
9
chocotan 2019-12-21 12:18:36 +08:00
楼上都说完了,我说个题外话
---- 最近运行时拿泛型头都大了 ( dubbo 泛化调用子属性有泛型就 gg,得手动传 class 进去,我一个消费端,还得服务端告诉我子属性是什么类型?于是在服务端折腾反射拿泛型类型,泛型如果是个 List,List 里面又是个泛型,整个人都蒙圈了。。。我用 spring mvc 没问题,用你 dubbo 就得客户端传类型给你?虽然最后是勉强完成了。。。 |