17

次のクラスでは、2つのメソッドの戻り型は、三項演算子という考え方と矛盾しています。

return condition?a:b;

と同等です

if(condition) {
    return a;
} else{ 
    return b;
}

1つ目はDoubleを返し、2つ目はLongを返します。

public class IfTest {
    public static Long longValue = 1l;
    public static Double doubleValue = null;

    public static void main(String[] args) {
        System.out.println(getWithIf().getClass());// outpus Long
        System.out.println(getWithQuestionMark().getClass());// outputs Double
    }

    public static Object getWithQuestionMark() {
        return doubleValue == null ? longValue : doubleValue;
    }

    public static Object getWithIf() {
        if (doubleValue == null) {
            return longValue;
         } else {
            return doubleValue;
        }
    }
}

これは、コンパイラのリターン型のナローキャストに関係していると想像できますが、getWithQuestionMark()その言語は大丈夫ですか?それは確かに私が期待したものではありません。

どんな洞察も大歓迎です!

編集:以下に非常に良い答えがあります。さらに、@ sakthisundarによって参照される次の質問は、三項演算子で発生する型昇格の別の副作用を調査します。Javaのトリッキーな三項演算子-オートボクシング

4

2 に答える 2

14

基本的に、JLS のセクション 15.25 の規則に従っています。具体的には、次のとおりです。

それ以外の場合、2 番目と 3 番目のオペランドが数値型に変換可能な型 (§5.1.8) を持っている場合は、いくつかのケースがあります。

  • [...]

  • それ以外の場合、2 進数値昇格 (§5.6.2) がオペランドの型に適用され、条件式の型は 2 番目と 3 番目のオペランドの昇格された型になります。

したがって、セクション 5.6.2に従います。これには、基本的にボックス化解除が含まれます。これにより、式がlongValueanddoubleValueがそれぞれ型longandであったかのように機能し、全体的な結果の型を取得するためにdouble拡張プロモーションが に適用されます。longdouble

次に、メソッドからdoubleを返すためにボックス化されます。Object

于 2012-08-24T12:03:19.540 に答える
3

@Jonの回答に加えて、表示されるバイトコードを見てください:

public static java.lang.Object getWithQuestionMark();
  Code:
   0:   getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   3:   ifnonnull       16
   6:   getstatic       #8; //Field longValue:Ljava/lang/Long;
   9:   invokevirtual   #9; //Method java/lang/Long.longValue:()J
   12:  l2d
   13:  goto    22
   16:  getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   19:  invokevirtual   #10; //Method java/lang/Double.doubleValue:()D
   22:  invokestatic    #11; //Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
   25:  astore_0
   26:  aload_0
   27:  areturn

一方、数値に興味がないことをコンパイラーに伝えた場合:

public static Object getWithQuestionMark() {
    return doubleValue == null ? (Object)longValue : (Object)doubleValue;
}

あなたはあなたが求めていたものを手に入れるでしょう(バイトコード)

public static java.lang.Object getWithQuestionMark();
  Code:
   0:   getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   3:   ifnonnull       12
   6:   getstatic       #8; //Field longValue:Ljava/lang/Long;
   9:   goto    15
   12:  getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   15:  areturn

出力:

$ java IfTest
class java.lang.Long
class java.lang.Long
于 2012-08-24T12:10:57.787 に答える