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

时间:2012-04-21 15:55:50

标签: java

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

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结构。有什么想法为什么编译器会这样做?

4 个答案:

答案 0 :(得分:3)

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。)

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

现在,您正尝试使用Objectinstanceof强制转换为正确的类型。到目前为止一直很好(但设计有点争议)。不幸的是,必须在编译时解析三元运算符表达式类型。 TreeItemTree的最具体的常见超类是Widget,与此方法相比:

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

smartCast不能包含Widget之外的任何其他返回类型,就像您的三元运营商一样。

答案 3 :(得分:1)

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

它给出奇怪错误的原因,构造函数Test(Object& Serializable& Comparable)是因为Integer和String都继承自那些3(Object,Serializable,Comparable)。所以在编译时,如果你有一个构造函数接受其中任何一个,Java会知道你想要使用那个。

与Tree和TreeItem相同。他们共同的父母是Widget。所以它需要1个构造函数来获取这两个项目。

它无法在运行时选择两个不同的构造函数之间用于一个新语句。