关于 Java 中类型擦除的一些疑惑

2019-12-20 14:04:33 +08:00
 codergrowing

问题的起因是在我使用 Spring 的BeanUtils.copyProperties方法时发现两个 POJO 如果拥有相同的字段名,即使泛型类型不同,值也会被拷贝过去。例如类 A 有一个类型为List<Integer>的字段 integerList,类 B 有一个类型为List<String>的字段也叫 integerList,那么使用 BeanUtils.copyProperties(b, a)时,integerList 字段会被拷贝过去。这时我想起了 Java 的类型擦除问题。我想问:

  1. 上述问题是因为类型擦除导致的吗
  2. 网上很多文章都是说类型擦除是发生在编译时,即编译后的 class 文件已经没有泛型类型信息了。但 class 文件反编译后的确还是有泛型信息的,如下图。所以类型擦除究竟发生在哪个阶段?

  1. 如下的代码中,通过打断点可以看到 method 的 signature 字段是有泛型类型信息的,而这已经是运行时了,为什么泛型类型信息还在?
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());
    }

4077 次点击
所在节点    Java
9 条回复
octobersnow
2019-12-20 14:08:01 +08:00
我记得类型擦出的确在编译阶段,但是字节码中貌似还是有相关的信息。
IMCA1024
2019-12-20 14:08:31 +08:00
点进去源码不是可以看了吗
cheng6563
2019-12-20 15:02:49 +08:00
局部变量里的泛型运行时没有任何作用。其他地方的泛型可以从反射 API 里读到,可以人工判断,但就算不判断也能塞不同的类型进去。
iffi
2019-12-20 15:57:07 +08:00
擦除是防止编译期间 不匹配的数据能写入。Class 记录了泛型类型。运行时是能获取泛型信息的。
palmers
2019-12-20 16:01:40 +08:00
泛型擦除的结论是没有问题的, 只不过现在 class 文件确实记录了泛型信息 - Signature Attribute,所以 javap 等反编译工具很多都可以解析到泛型信息, 但是这个泛型信息并不是给 jvm 用的, 具体规范这里有详细的描述:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
palmers
2019-12-20 16:07:46 +08:00
kilen3a
2019-12-20 16:21:50 +08:00
字节码的泛型是反射和 debug 时用的(获取当然也只能通过反射),泛型擦除在编译器发生这个说法没问题,而且运行时 JVM 不会使用到 class 常量池中的泛型
kilen3a
2019-12-20 16:26:21 +08:00
chocotan
2019-12-21 12:18:36 +08:00
楼上都说完了,我说个题外话
----
最近运行时拿泛型头都大了
( dubbo 泛化调用子属性有泛型就 gg,得手动传 class 进去,我一个消费端,还得服务端告诉我子属性是什么类型?于是在服务端折腾反射拿泛型类型,泛型如果是个 List,List 里面又是个泛型,整个人都蒙圈了。。。我用 spring mvc 没问题,用你 dubbo 就得客户端传类型给你?虽然最后是勉强完成了。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/630824

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX