首页 > 开发中遇到的一个java泛型的问题

开发中遇到的一个java泛型的问题

    private static List<String> getList(String content){
//        return content==null ? Collections.emptyList():new ArrayList<String>();//error: cannot convert from List<capture#1-of ? extends Object> to List<String>
//        return content==null ? Collections.<String>emptyList():new ArrayList<String>();//ok
          return Collections.emptyList();//ok
    }

为什么第一种方法要报错,但最后一种却可以?


首先你方法的返回值是List<String>,所以你需要return这个类型的对象。
其实答案就是Collections.emptyList()其实是Object类型的List,而你的返回值要求都是String类型的List,所以肯定报错呀。


因为使用了 expression?expression:expression这样的语句,所以有问题。
如果你用if语句就没问题了。

Collections.emptyList()的泛型取决于它要赋予的变量(或返回值等)的类型,所以最后一个是对的。
但是,【expression?expression:expression】这个语句的结果会有一个默认的Object来接收,
然后在转换成要赋予的变量的类型,那么导致Collections.emptyList()给Object类型赋值,无法判断泛型,所以报错。
通过实验可以验证,如下:
Object a = content==null ? "2":1;


  1. 经测试,如下这行代码在jdk8下是不报错的(jdk7应该也是可以的,但暂时没有测试)。而之前这里的报错是在jdk6环境下。

return content==null ? Collections.emptyList():new ArrayList<String>();//error: cannot convert from List<capture#1-of ? extends Object> to List<String>
  1. 再测试,如下代码在jdk6下也是OK的。

return content==null ? Collections.emptyList():new ArrayList();

也就是说三目运算符的两个返回类型都是原始List类型就可以。
对比上面的报错,可以初步判定编译出错原因是,因为编译时就可以通过new ArrayList<String>可以推断出方法返回类型是List<String>(String泛型类型已经被记录),而Collections.emptyList()又是原始List类型.如果运行时返回后者原始List,就可能出现convert from List<capture#1-of ? extends Object> to List<String>。而现在,在编译时就直接报错来避免这种运行时的强转错误。
因此,返回两个原始类型可以编译通过这个也能解释了,因为编译时并不能确定下他们的确切返回类型(根据类型擦除原理,实际方法返回类型是List<Object>),所以两种返回convert from List<capture#1-of ? extends Object> to List<Object>是OK的。

以上只是个人测试下半猜测的结论,并没有Oracle相关文档支持,如果有错误,请大家指正。


出错原因是你使用了一个引用条件表达式(reference conditional expression)来给变量赋值,并且你的java se版本不是8.0

由于条件表达式不在变量赋值或者调用的上下文中,属于standalone reference conditional expression,这种表达式的类型推断有三条的规则:

  1. 当第二、第三表达式类型相同时,该类型作为条件表达式的类型

  2. 当第二、第三表达式类型其中之一是 null type,另一个是引用类型,引用类型作为条件表达式的类型

  3. 当第二、第三表达式类型分别为s1、 s2,t1、t2分别为s1、s2经过自动装箱转换后的类型,则 应用过capture conversion 的lub(t1, t2)为表达式类型

由于你的条件表达式第二个和第三个表达式类型不一样,分别是 List<T> 和 List<String> ,由于没有给emptyList()指定类型,所以这里T是Object。适用第三条规则,最终的类型是 lub(List<Object>, List<String>) ,lub是 least upper bound 的缩写,在这里指最小公共上界,结果是 List<? extends Object>。
至于 capture conversion,主要是为了从含有通配符的泛型中推断公共上界,我不清楚在这里对类型有没有贡献,猜测没有。

所以到最后赋值的时候会报错,因为赋值类型和表达式类型不匹配。


没什么好讨论的,和JAVA版本有关,了解下 类型推断 这个东西就行了。

【热门文章】
【热门文章】