zoukankan      html  css  js  c++  java
  • 转:有关Java泛型的类型擦除(type erasing)

    转载自:拈花微笑

    自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资。在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结论是

    • Java使用类型擦除(type erasing),泛型信息只在编译时供javac作类型检查用,在编译后便被javac擦除,因此无法被反射
    • C++使用代码模板实现泛型,即在预处理时会生成类似「list_int」,「list_char」等的泛型类,虽然解决Java的运行时伪泛型的问题,但是会导致编译后的代码呈线性增长
    • 于是在一般情况下,Java的类型擦除实现较优

    这三条已经比绝大多数的Java培训讲师讲得深刻了。但是如果下面有人问「在什么情况下C++的实现方式较优」时,除了无法被反射,我很难现抓一个有说服力的例子。今天,Spring的RestTemplate终于给了我这个例子

    我遇到的问题如下(阅读需要有一些Spring MVC、REST基础)

    有一个返回类型为List的MVC方法:

     Java |     copy code | ?  
    1  
    2
    @RequestMapping(value = "...", method = RequestMethod.GET)
    3
    @ResponseBody
    4
    public List<DomainClass> doSomethingREST() {
    5
        List<DomainClass> domainObjs = ... ;
    6
        return domainObjs;
    7
    }
    8  

    在运行时,Spring MVC会将List转换成JSON字符串并返回至客户端。但是如果我在另一个service中使用RestTemplate直接调用该REST接口,问题便来了:

     Java |     copy code | ?  
    1  
    2
    List<DomainClass> domainObjs = this.restTemplate.getForObject(this.restURL, List.class);
    3  

    关键在于第二个参数,是返回值的类型,RestTemplate会根据此类型选择适当的MessageConverter将调用REST接口的返回值反序列化为与类型匹配的对象。由于List的泛型参数在编译时被擦除,于是RestTemplate便无法确定List中的内容。「一般情况下」(REST接口返回值不是List类型)不会有问题,但是巧合的是,如果服务器端使用JSON对REST结果进行序列化,返回值会被封装在List中,此时,Spring已无法判断开发人员是想直接获得List封装的JSON内容还是需要更进一步使用Jackson库将JSON反序列化为Java对象。现实情况下,Spring选择的前者,于是便会抛出ClassCastException

    上网搜了一圈,已经有人向Spring提交了enhancement请求(这里这里,其中第一个链接中的walkaround可以work),但是目前没有milestone
     

    – EOF –

  • 相关阅读:
    高可用keepalived的抢占式与非抢占式
    keepalived搭建
    高可用概念
    Nginx优雅显示错误页面
    Nginx调整上传文件大小
    nginx的root和alias区别
    nginx的include
    每日总结2.18
    每日总结2.17
    每日总结2.16
  • 原文地址:https://www.cnblogs.com/timlong/p/3916240.html
Copyright © 2011-2022 走看看