简体   繁体   English

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

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

Recently I have got a compilation error in the code below: 最近,我在以下代码中遇到了编译错误:

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

Compiler says: "The constructor TreeItem(Widget, int) is undefined" 编译器说:“构造函数TreeItem(Widget,int)未定义”

Then I have tried it with another code: 然后我尝试了另一个代码:

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){}
}

And got another error: "The constructor Test(Object&Serializable&Comparable) is undefined" 并得到另一个错误:“构造函数Test(Object&Serializable&Comparable)未定义”

So I was forced to use the traditional if-else structure. 因此,我不得不使用传统的if-else结构。 Any ideas why the compiler behaves so? 有什么想法为什么编译器会这样?

JLS §15.25 describes the ternary operator. JLS§15.25描述了三元运算符。

Otherwise, the second and third operands are of types S1 and S2 respectively. 否则,第二和第三操作数分别为S1和S2类型。 Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. 令T1为对S1进行装箱转换所产生的类型,而T2为对S2进行装箱转换所产生的类型。

The type of the conditional expression is the result of applying capture conversion ( §5.1.10 ) to lub(T1, T2) ( §15.12.2.7 ). 条件表达式的类型是将捕获转换(第5.1.10节 )应用于lub(T1,T2)(第15.12.2.7节 )的结果。

Basically, you can think of the ternary operator as a method: it can only have one "return type". 基本上,您可以将三元运算符视为一种方法:它只能具有一个“返回类型”。 Since String and Integer are two different objects, it finds the common superclass and all interfaces implemented by both and creates a return type from that. 由于StringInteger是两个不同的对象,因此它会找到通用的超类和两者都实现的所有接口,并从中创建一个返回类型。 ( String and Integer both implement Serializable and Comparable and extend Object , so you get Object & Serializable & Comparable .) StringInteger都实现了SerializableComparable并扩展了Object ,因此您获得了Object & Serializable & Comparable 。)

The reason is very simple: the Ternary-Operators result is a static type. 原因很简单:三元运算符的结果是静态类型。 When making such a typecasting, the type that will returned is the common ancestor of the type used in both possible results. 进行此类类型转换时,将返回的类型是在两种可能的结果中使用的类型的公共祖先。 In your first example widget is the common ancestor of TreeItem and Tree, in the second example the common ancestor from String and Integer is Object. 在第一个示例中,小部件是TreeItem和Tree的共同祖先,在第二个示例中,String和Integer的共同祖先是Object。 So when you use the result of such an operation for a new operation, you need a constrcutor for that common type. 因此,当您将此类操作的结果用于新操作时,您需要该通用类型的构造函数。

Seems like we are talking about this TreeItem class. 好像我们在谈论这个TreeItem类。 Note that the constructor accepts either Tree or TreeItem . 请注意,构造函数接受TreeTreeItem

Now, you are trying to cast that Object to correct type using instanceof . 现在,您尝试使用instanceof将该Object为正确的类型。 So far so good (however the design is a bit controversial). 到目前为止,一切都很好(但是设计有点争议)。 Unfortunately the ternary operator expression type must be resolved at compile time. 不幸的是,三元运算符表达式类型必须在编译时解析。 The most specific common super class of both TreeItem and Tree is Widget , compare with this method: TreeItemTree的最特定的公共超类是Widget ,与此方法进行比较:

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

smartCast cannot have any other return type than Widget , just like your ternary operator. 像您的三元运算符一样, smartCast不能具有Widget以外的任何其他返回类型。

when creating an object it looks like java needs to know which specific constructor you want to use at Compile time. 创建对象时,java似乎需要知道要在编译时使用哪个特定的构造函数。

The reason its giving that odd error, The constructor Test(Object&Serializable&Comparable) is because Integer and String both inherit from those 3 (Object, Serializable, Comparable). 之所以产生这种奇怪的错误,是因为构造函数Test(Object&Serializable&Comparable)是因为Integer和String都继承自这3个对象(Object,Serializable,Comparable)。 And so at compile time, if you had a constructor which took any of those, Java would know you want to use that one. 因此,在编译时,如果您有一个采用了其中任何一种的构造函数,Java就会知道您想使用该构造函数。

Its the same with Tree and TreeItem. 与Tree和TreeItem相同。 Their common parent it Widget. 他们共同的父母是Widget。 So it needs 1 constructor that can take both items. 因此,它需要1个可以同时使用这两个项目的构造函数。

It cant at Runtime pick between 2 different constructors for one new statement. 它无法在运行时为两个新构造函数选择一个新语句。

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

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