8

次のプログラムは、それぞれ「false」と「true」を出力します。

Number n = true ? new Long(1) : new Double(2.0);
System.out.println(n instanceof Long);
System.out.println(n instanceof Double);

したがって、ロングではなくダブルになります。ただし、通常のクラスでは意図したとおりに機能します。

class B {}
class D1 extends B {}
class D2 extends B {}

これは「true」を出力します:

B b = true ? new D1() : new D2();
System.out.println(b instanceof D1);

これは、上記の例と同じようには機能しないことを意味します。

オートボクシングに関連するものがあると確信していますが、それは本当にそれが機能するはずの方法ですか?NumberクラスがLongとDoubleの両方のスーパークラスであるのに、式をNumberに評価できるように、なぜ彼女はボクシングを使用するのですか?

nを出力すると、double値として出力されるため、これは本当に面倒です。(回避するのは簡単ですが、私を夢中にさせました)

4

2 に答える 2

7

ここで言語弁護士の本を取り出しましょう: JLS §15.25

条件式のタイプは、次のように決定されます。

  • 2 番目と 3 番目のオペランドが同じ型 (null 型の場合もある) の場合、それが条件式の型になります。

Long と Double は同じ型ではありません - 適用されません。

  • 2 番目と 3 番目のオペランドの一方がプリミティブ型 T で、もう一方の型が T にボックス化変換 (§5.1.7) を適用した結果である場合、条件式の型は T です。

どちらの値もプリミティブではありません - 適用されません。

  • 2 番目と 3 番目のオペランドの一方が null 型で、もう一方の型が参照型である場合、条件式の型はその参照型になります。

どちらの値もヌルではありません - 適用されません。

  • それ以外の場合、2 番目と 3 番目のオペランドが数値型に変換可能な型 ( §5.1.8 ) を持っている場合、いくつかのケースがあります。
    • [... byte/short/char およびそれらのボックス化された等価物の特殊なケース...]
    • それ以外の場合、バイナリ数値昇格 (§ 5.6.2 ) がオペランドの型に適用され、条件式の型は 2 番目と 3 番目のオペランドの昇格された型になります。

このルールはここでも適用されます。つまり、条件演算子の結果の型は、両方の値がボックス化されていないかのようになります。その背後にある理由は、それ以外の場合であり、異なる値Number n = bool ? 1 : 2.0を持っていると考えられます. Number n = bool ? new Long(1) : new Double(2.0)この動作も予期しないものであり、さらに悪いことに、一貫性がありません。

于 2012-10-08T20:46:07.357 に答える
2

単純にバイトコードを見るとわかります(単に例を変更しただけです)

Number n = true ? new Long(166666) : new Double(24444.0);
System.out.println(Boolean.toString(n instanceof Long));
System.out.println(Boolean.toString(n instanceof Double));

バイトコード

_new 'java/lang/Long'

dup
ldc 166666
invokespecial 'java/lang/Long.<init>','(J)V'
invokevirtual 'java/lang/Long.longValue','()J'
l2d
invokestatic 'java/lang/Double.valueOf','(D)Ljava/lang/Double;'
astore 1

主なポイントはl2d、次のステップを作成することです

long 整数をスタックからポップし、倍精度浮動小数点数にキャストして、倍精度浮動小数点数をスタックにプッシュします。これにより、精度が失われる可能性があります (double の有効桁数は long の 64 ビットに対して 54 ビットです) が、大きさが失われることはありません (double の範囲は long の範囲よりも大きいため)。丸めは、IEEE 754 round-to-nearest モードを使用して行われます。

そして、この後はすべて良いので、Doubleインスタンスがありますが、Long Valueがあります! デバッグ モードで見ると、数値は Double ですが、Long の値であることがわかります。上記のバイト コードで説明されています

バイトコードで見ることができます

getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
aload 1
_instanceof 'java/lang/Long'
invokestatic 'java/lang/Boolean.toString','(Z)Ljava/lang/String;'
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/String;)V'
getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
aload 1
_instanceof 'java/lang/Double'
invokestatic 'java/lang/Boolean.toString','(Z)Ljava/lang/String;'
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/String;)V'
return
于 2012-10-08T20:50:08.573 に答える