列表初始化时出现奇怪的错误

时间:2015-07-24 19:40:21

标签: java generics

我的一位朋友问我是否可以帮助他找出错误背后的原因,他正在编写一段代码,并且最重要的是为什么错误会在添加一些代码时消失。我已经查看了有关课程的文档,但也无法找到原因。

以下是代码:

import java.util.Arrays;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;

public class Test {

    public static void main(String[] args) {
        /**
        * This line shows this compilation error in eclipse:
        * Type mismatch: cannot convert from 
        *     List<Class<? extends JComponent&Accessible>> 
        *          to List<Class<? extends JComponent>>
        */
        List<Class<? extends JComponent>> listComp = Arrays.asList(JTabbedPane.class, 
                                                                   JPanel.class);

        /**
        * This one compiles fine and the difference is that
        * he added JComponent.class on the list and the 
        * code is working fine
        */
        List<Class<? extends JComponent>> listComp2 = Arrays.asList(JTabbedPane.class, 
                                                                    JPanel.class, 
                                                                    JComponent.class);
    }

}

正如您所看到的,唯一的区别是在第二个列表变量中我们添加了JComponent.class并且错误消失了。

为什么?

更新

我们正在使用Java JDK 7 update 80

更新2

另一位朋友建议使用这段代码,它也有效:

List<Class<? extends JComponent>> listComp = 
      new ArrayList<Class<? extends JComponent>> ( Arrays.asList( JTabbedPane.class, 
                                                                  JPanel.class));

1 个答案:

答案 0 :(得分:8)

我可以在Java 7中复制此问题,但是当我切换到Java 8时,不再给出错误。另外,如果我留在Java 7中,但我给Arrays.asList一个类型参数,则不再给出错误。

List<Class<? extends JComponent>> listComp =
    Arrays.<Class<? extends JComponent>>asList(JTabbedPane.class, JPanel.class);

Java将尝试确定Arrays.asList返回的目标类型。显然,JTabbedPaneJPanel都会延伸JComponent并实施Accessible。但是,JComponent并未实现Accessible。结果是编译器可以从所有类型中获得的最完整,特定的类型。对于您的第一个示例,推断类型为List<Class<? extends JComponent & Accessible>>,因为两个参数都适合该类型。添加JComponent时,推断类型现在为List<Class<? extends JComponent>>且匹配listComp,允许它在Java 7中编译。

Java 8功能改进了target type inference。该教程的示例是将Collections.emptyList传递给需要List<String>的方法。在Java 7中,推断类型将为List<Object>,并且会发生编译错误。但是,在Java 8中,推断类型为List<String>,与方法的参数匹配,代码编译。

这与您的代码完全相同,但它足够接近我相信Java 8的改进目标类型推断解释了为什么代码会使用该版本进行编译