web-dev-qa-db-ja.com

自動ボクシングはvalueOf()を呼び出しますか?

次の記述が正しいことが保証されているかどうかを判断しようとしています。

_((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)
_

自動ボクシングは、対応する型でvalueOf()を呼び出すことと同等であると常に想定してきました。 トピック で見たすべての ディスカッションサポート 私の仮定のようです。しかし、私がJLSで見つけたのは、次のことだけでした( §5.1.7 ):

ボックス化されている値pが、_-128_と_127_の間のタイプintの整数リテラル(§3.10.1)、またはブールリテラルtrueまたはfalse(§3.10.3)、または_'\u0000'_と_'\u007f'_の間の文字リテラル(§3.10.4)の場合、abは、pの任意の2つのボクシング変換の結果です。 _a == b_は常に当てはまります。

それは行動を説明します 同一valueOf()と同様*。ただし、valueOf()が実際に呼び出されるという保証はないようです。つまり、理論的には、自動ボックス化された値用に個別の専用キャッシュを保持する実装が存在する可能性があります。このような場合、キャッシュされた自動ボックス化された値と通常のキャッシュされたボックス化された値の間に同一性がない可能性があります。

Oracleのオートボクシングチュートリアル は、li.add(i)li.add(Integer.valueOf(i))にコンパイルされることを事実上述べています。ここで、iintです。 。しかし、チュートリアルを信頼できる情報源と見なすべきかどうかはわかりません。


*リテラル値のみを参照するため、valueOf()よりもわずかに弱い保証です。

50
shmosel

私は最初にあなたの質問が コンパイラがオートボクシングのために生成するコードの重複だと思いましたか?

しかし、@ ElliottFrischにコメントした後、私はそれが違うことに気づきました:

私はコンパイラがそのように動作することを知っています。私はその振る舞いが保証されているかどうかを理解しようとしています。

他の読者の場合、「そのように動作する」とはvalueOfを使用することを意味すると想定します。

Javaには複数のコンパイラがあることに注意してください。 「合法」であるためには、 [〜#〜] jls [〜#〜] で与えられた契約に従わなければなりません。したがって、ここでのすべてのルールが尊重されている限り、オートボクシングが内部でどのように実装されているかは保証されません。

しかし、valueOfを使用しない理由はわかりません。特に、キャッシュされた値を使用し、 この記事 に従って推奨される方法です。 -)ジョセフD.ダーシーによる。

29

言語仕様で言及されるまで、自動ボクシングが静的valueOfメソッドの呼び出しと同等であるとは限りません。これは実装の側面であり、ボクシング変換仕様の一部ではありません。実装は、JLSから言及したルールに準拠している限り、理論的には別のメカニズムを自由に使用できます。

実際には、多くのSun JDKバグレポート(例: JDK-4990346 および JDK-6628737 )があり、オートボクシングがJava 5、意図は、 JDK-6628737 で述べられているように、コンパイラにvalueOfに依存させることでした。

静的ファクトリメソッドInteger.valueOf(int)、Long.valueOf(long)などは、自動ボクシング仕様で必要なキャッシュ動作を実装するために、javac用のJDK5で導入されました。

ただし、これはjavacのみであり、必ずしもすべてのコンパイラであるとは限りません。

18
manouti

オートボクシングisは、OpenJDKのvalueOf()...を使用して絶対に実装されています。それがあなたの実装である場合は、読み進めてください...そうでない場合は、以下にスキップしてください。

_((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
_

Javaのドキュメントには、Boolean.valueOf()は常に_Boolean.TRUE_または_Boolean.FALSE_を返すと記載されているため、これらの場合の参照比較は成功します。

_((Integer)1) == Integer.valueOf(1)
_

この特定の例では、デフォルト設定のOpenJDK実装では、起動時にキャッシュされる128未満の値を選択したため、おそらく機能します(ただし、これは可能です)コマンドライン引数としてオーバーライドされます)。キャッシュするのに十分な頻度で頻繁に使用される場合は、mayも大きな値に対して機能します。整数キャッシュに関する「安全な」仮定の下で作業しているのでない限り、参照比較が等しいと期待しないでください。

LongShortCharacter、およびByteも偶然にもこのキャッシュを実装していますが、Integerとは異なり、調整できません。 autobox/valueOf()参照を比較している場合は、明らかに範囲外に出ることはできないため、Byteは常に機能します。 FloatDoubleは、当然のことながら常に新しいインスタンスを作成します。


さて、純粋に一般的な用語で? JLSのこのセクションを参照 -あなた[〜#〜] must [〜#〜]booleanの同等の参照を指定する必要がありますおよび-128から127の範囲内のintまたはchar。他には保証はありません

4
Olipro