0

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

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

4 回答 4

3

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

否则,第二个和第三个操作数分别是 S1 和 S2 类型。令 T1 为对 S1 应用装箱转换产生的类型,令 T2 为对 S2 应用装箱转换产生的类型。

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

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

于 2012-04-21T16:03:57.577 回答
1

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

于 2012-04-21T16:04:15.533 回答
1

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

现在,您正在尝试Object使用instanceof. 到目前为止一切都很好(但是设计有点争议)。不幸的是,三元运算符表达式类型必须在编译时解析。和 最具体的常见超类是,TreeItem与此方法进行比较:TreeWidget

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

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

于 2012-04-21T16:04:15.557 回答
1

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

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

它与 Tree 和 TreeItem 相同。他们共同的父它Widget。所以它需要 1 个可以同时接受这两个项目的构造函数。

它不能在运行时为一个新语句选择 2 个不同的构造函数。

于 2012-04-21T16:04:46.883 回答