我的一位朋友问我是否可以帮助他找出错误背后的原因,他正在编写一段代码,并且最重要的是为什么错误会在添加一些代码时消失。我已经查看了有关课程的文档,但也无法找到原因。
以下是代码:
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));
答案 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
返回的目标类型。显然,JTabbedPane
和JPanel
都会延伸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的改进目标类型推断解释了为什么代码会使用该版本进行编译