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では、三項演算子について説明しています。

それ以外の場合、2番目と3番目のオペランドはそれぞれタイプS1とS2です。T1をS1にボクシング変換を適用した結果のタイプとし、T2をS2にボクシング変換を適用した結果のタイプとします。

条件式のタイプは、キャプチャ変換(§5.1.10)をlub(T1、T2)(§15.12.2.7)に適用した結果です。

基本的に、三項演算子はメソッドと考えることができます。「戻り型」は1つだけです。Stringとは2つの異なるオブジェクトであるためInteger、両方によって実装された共通のスーパークラスとすべてのインターフェイスを検出し、そこからリターンタイプを作成します。(StringそしてInteger、実装SerializableComparable拡張Objectの両方があるので、取得しますObject & Serializable & Comparable。)

于 2012-04-21T16:03:57.577 に答える
1

理由は非常に単純です。Ternary-Operatorsの結果は静的型です。このような型キャストを行う場合、返される型は、両方の可能な結果で使用される型の共通の祖先です。最初の例では、ウィジェットはTreeItemとTreeの共通の祖先であり、2番目の例では、StringとIntegerの共通の祖先はObjectです。したがって、そのような操作の結果を新しい操作に使用する場合は、その一般的なタイプのコンストラクターが必要です。

于 2012-04-21T16:04:15.533 に答える
1

TreeItemこのクラスについて話しているようです。Treeコンストラクターはまたはのいずれかを受け入れることに注意してくださいTreeItem

今、あなたはそれObjectを正しいタイプにキャストしようとしていますinstanceof。これまでのところ良いです(ただし、デザインは少し物議を醸しています)。残念ながら、三項演算子の式の型はコンパイル時に解決する必要があります。TreeItemとの両方の最も具体的な一般的なスーパークラスTreeWidget、このメソッドと比較してください。

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

smartCastWidget三項演算子のように、以外の戻り値を持つことはできません。

于 2012-04-21T16:04:15.557 に答える
1

オブジェクトを作成するとき、Javaはコンパイル時に使用する特定のコンストラクターを知る必要があるように見えます。

その奇妙なエラーを与える理由は、コンストラクターTest(Object&Serializable&Comparable)は、整数と文字列の両方がこれら3つ(Object、Serializable、Comparable)を継承しているためです。したがって、コンパイル時に、これらのいずれかを使用するコンストラクターがある場合、Javaはそのコンストラクターを使用することを認識します。

TreeやTreeItemでも同じです。彼らの共通の親はウィジェットです。したがって、両方のアイテムを受け取ることができる1つのコンストラクターが必要です。

実行時に、1つの新しいステートメントに対して2つの異なるコンストラクターを選択することはできません。

于 2012-04-21T16:04:46.883 に答える