繁体   English   中英

由于类型检查或三元运算符而导致编译错误?

[英]Compile error because of type check or ternary operator?

最近,我在以下代码中遇到了编译错误:

import org.eclipse.swt.widgets.TreeItem;
Object parent; // can only be a Tree or a TreeItem    
...
TreeItem item = new TreeItem((parent instanceof TreeItem) ? (TreeItem) parent : (Tree) parent, SWT.NONE);

编译器说:“构造函数TreeItem(Widget,int)未定义”

然后我尝试了另一个代码:

Object x = new Integer(1);

Test t = new Test((x instanceof String) ? (String) x : (Integer) x);

class Test{
    public Test(String s){}
    public Test(Integer i){}
}

并得到另一个错误:“构造函数Test(Object&Serializable&Comparable)未定义”

因此,我不得不使用传统的if-else结构。 有什么想法为什么编译器会这样?

JLS§15.25描述了三元运算符。

否则,第二和第三操作数分别为S1和S2类型。 令T1为对S1进行装箱转换所产生的类型,而T2为对S2进行装箱转换所产生的类型。

条件表达式的类型是将捕获转换(第5.1.10节 )应用于lub(T1,T2)(第15.12.2.7节 )的结果。

基本上,您可以将三元运算符视为一种方法:它只能具有一个“返回类型”。 由于StringInteger是两个不同的对象,因此它会找到通用的超类和两者都实现的所有接口,并从中创建一个返回类型。 StringInteger都实现了SerializableComparable并扩展了Object ,因此您获得了Object & Serializable & Comparable 。)

原因很简单:三元运算符的结果是静态类型。 进行此类类型转换时,将返回的类型是在两种可能的结果中使用的类型的公共祖先。 在第一个示例中,小部件是TreeItem和Tree的共同祖先,在第二个示例中,String和Integer的共同祖先是Object。 因此,当您将此类操作的结果用于新操作时,您需要该通用类型的构造函数。

好像我们在谈论这个TreeItem类。 请注意,构造函数接受TreeTreeItem

现在,您尝试使用instanceof将该Object为正确的类型。 到目前为止,一切都很好(但是设计有点争议)。 不幸的是,三元运算符表达式类型必须在编译时解析。 TreeItemTree的最特定的公共超类是Widget ,与此方法进行比较:

public Widget smartCast(Object parent) {
    if(parent instanceof TreeItem) {
        return (TreeItem)parent;
    } else {
        return (Tree)parent;
    }
}

像您的三元运算符一样, smartCast不能具有Widget以外的任何其他返回类型。

创建对象时,java似乎需要知道要在编译时使用哪个特定的构造函数。

之所以产生这种奇怪的错误,是因为构造函数Test(Object&Serializable&Comparable)是因为Integer和String都继承自这3个对象(Object,Serializable,Comparable)。 因此,在编译时,如果您有一个采用了其中任何一种的构造函数,Java就会知道您想使用该构造函数。

与Tree和TreeItem相同。 他们共同的父母是Widget。 因此,它需要1个可以同时使用这两个项目的构造函数。

它无法在运行时为两个新构造函数选择一个新语句。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM