== Integer.valueOf(String)との比較で127と128の結果が異なるのはなぜですか?


182

これらのコード行が異なる値を返す理由はわかりません。

System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));

出力は次のとおりです。

true
false
true

なぜ最初のものが戻ってきtrueて、2番目のものが戻ってくるのfalseですか?との間でわからないことは127あり128ますか?(もちろん、私はそれを知っています127< 128

また、なぜ3番目のものが返されるのtrueですか?

私はこの質問の回答読みましたが、それがどのように返されるのtrueか、2行目のコードが返される理由はまだわかりませんfalse


6
整数はオブジェクトです。等しいかどうかを比較する場合はを使用.equals()します。それ以外の場合はすべての賭けがオフになります。
Karl Damgaard Asmussen 2014年

6
@KarlDamgaardAsmussen実際、ここでは、それらが同じオブジェクトへの参照であるかどうかを実際にテストしたいのですが、最初は127 128が異なる結果を返す理由がわかりません。
DnR 2014年

@DnR Javaが標準化された仕様の言語である場合、そのような問題は実装に任せるか、未定義の動作を強制することさえできると思います。
Karl Damgaard Asmussen、2014年

1
@jszumski:ただし、この質問には、キャッシュ部分だけではありません。そのうえ、リンクされた回答はせいぜい不完全です-何がキャッシュされるのか、なぜそうなるのかについては、詳しくは触れていません。

1
このディスカッションの詳細については、このメタ投稿を参照しください。
Jeroen Vannevel 2014年

回答:


191

ここには著しい違いがあります。

valueOfInteger-128から127までの値がキャッシュされているオブジェクトを返します。これが、最初の値が返されるtrue-キャッシュされる-そして2番目の値が返される-128 falseがキャッシュされた値ではないため、2つの別々のIntegerインスタンスを取得しているためです。

参照をと比較していることInteger#valueOf、およびキャッシュがサポートしている値より大きい値を比較している場合は、解析された値が同等であっても評価されないことに注意することが重要ですtrue(ケースインポイント:) Integer.valueOf(128) == Integer.valueOf(128)。代わりに使用する必要ありますequals()

parseIntはプリミティブを返しintます。これが、3番目の値が返される理由ですtrue- 128 == 128評価され、そしてもちろんですtrue

さて、かなりの偶然がその3番目の結果をもたらしtrueます:

  • アンボックス化変換は、使用している等価演算子と使用しているデータ型(つまり、intおよび)に関して発生しますInteger。もちろん、右側IntegerからvalueOfを取得しています。

  • 変換後、2つのプリミティブint値を比較します。プリミティブに関して期待するように比較が行われるので、とを比較することに128なり128ます。


2
@ user3152527:かなりの違いがあります-1つはオブジェクトと見なされます。つまり、メソッドを呼び出して、のような抽象的なデータ構造でオブジェクトと対話できますList。もう1つはプリミティブであり、これは単なる生の値です。
誠14年

1
@ user3152527あなたはすばらしい質問をしました(最悪の場合、ばかげた質問ではありません)。しかし、.equalsを使用するように修正しましたよね?
user2910265 2014年

3
ああ、質問者はJavaの根本的な事実を理解していなかったようです。「==」を使用して2つのオブジェクトを比較する場合、それらが同じオブジェクトへの参照であるかどうかをテストしています。「equals()」を使用する場合、それらが同じ値を持つかどうかをテストしています。「等しい」を使用してプリミティブを比較することはできません。
Jay

3
@ジェイ、いいえ、私はそれを理解しています。しかし、最初に混乱するのは、同じ比較方法を使用して最初のものがtrueを返し、2番目のものがfalseを返す理由==です。とにかく、今ははっきりしている。
DnR 2014年

1
Nit:Integerが-128から127の間でキャッシュされる可能性があるのは、それだけではありません。JLS5.1.7によれ、キャッシュされる必要あります。それはあり、その範囲の外にキャッシュされますが、なくてもかまいません(と、多くの場合ではありません)。
yshavit

127

このIntegerクラスには静的キャッシュがあり、Integer-128から127までのすべての値に1つずつ、256の特別なオブジェクトを格納します。このことを念頭に置いて、これら3つのオブジェクトの違いを考慮してください。

new Integer(123);

これは(明らかに)まったく新しいIntegerオブジェクトになります。

Integer.parseInt("123");

これは、のint解析後にプリミティブ値を返しますString

Integer.valueOf("123");

これは他のものより複雑です。まず、を解析しStringます。次に、値が-128から127の間の場合、静的キャッシュから対応するオブジェクトを返します。値がこの範囲外の場合は、値を呼び出しnew Integer()て渡し、新しいオブジェクトを取得します。

では、質問の3つの表現について考えてみましょう。

Integer.valueOf("127")==Integer.valueOf("127");

Integer値が127の静的キャッシュから2回取得され、それ自体と比較されるため、これはtrueを返します。Integer関係するオブジェクトは1つだけなので、これはを返しますtrue

Integer.valueOf("128")==Integer.valueOf("128");

false128は静的キャッシュにないため、これはを返します。したがってInteger、平等の両側に新しいものが作成されます。2つの異なるIntegerオブジェクトがあり==、オブジェクトがtrue両方の側がまったく同じオブジェクトである場合にのみ返されるため、これはになりますfalse

Integer.parseInt("128")==Integer.valueOf("128");

これはint、左側のプリミティブ値128をInteger右側の新しく作成されたオブジェクトと比較しています。しかし、それは比較することは意味がありませんのでintInteger、Javaの意志の自動UnboxのInteger比較を行う前に、つまり、とintを比較することになりintます。プリミティブ128はそれ自体と等しいため、これはを返しますtrue


13

これらのメソッドから値を返すことに注意してください。valueOfの方法は、整数のインスタンスを戻します。

public static Integer valueOf(int i)

parseIntの値(プリミティブ型)整数メソッドの戻り値:

public static int parseInt(String s) throws NumberFormatException

比較のための説明:

メモリを節約するために、ラッパーオブジェクトの2つのインスタンスは、プリミティブ値が同じ場合、常に==になります。

  • ブール
  • バイト
  • \ u0000から\ u007fまでの文字(7fは10進数で127)
  • -128から127までの短整数

==を使用してプリミティブとラッパーを比較すると、ラッパーがアンラップされ、比較はプリミティブとプリミティブになります。

あなたの状況では(上記のルールに従って):

Integer.valueOf("127")==Integer.valueOf("127")

この式は、同じオブジェクトへの参照を比較しますtrue。これは、-128から127までの整数値が含まれているために返されるためです。

Integer.valueOf("128")==Integer.valueOf("128")

この式は、<-128、127>にない整数値を含むため、異なるオブジェクトへの参照を比較して、を返しますfalse

Integer.parseInt("128")==Integer.valueOf("128")

この式は、プリミティブ値(左側)とオブジェクトへの参照(右側)を比較するため、右側がラップ解除され、そのプリミティブ型が左側と比較されてが返されますtrue



引用元のURLを教えてもらえますか?
Philzen

「...ラッパーオブジェクトの2つのインスタンスは、プリミティブ値が同じ場合、常に==になります...」 -完全に偽。同じ値で2つのラッパーオブジェクトを作成した場合、==それらは異なるオブジェクトであるため、と比較してもtrueを返しません。
Dawood ibnカリーム

6

整数オブジェクトは、256整数の-128から127までのキャッシュ

オブジェクト参照を==または!=と比較しないでください。使用する必要があります。代わりにequals(..)またはそれ以上-Integerではなくプリミティブintを使用してください。

parseInt:文字列引数を符号付き10進整数として解析します。文字列内の文字はすべて10進数である必要があります。ただし、最初の文字は負の値を示すためにASCIIマイナス記号「-」(「\ u002D」)である場合があります。結果の整数値が返されます。これは、引数と基数10がparseInt(java.lang.String、int)メソッドの引数として指定された場合とまったく同じです。

valueOf 2番目の引数で指定された基数で解析されたときに、指定されたStringから抽出された値を保持するIntegerオブジェクトを返します。最初の引数は、引数がparseInt(java.lang.String、int)メソッドに渡された場合とまったく同じように、2番目の引数で指定された基数で符号付き整数を表すと解釈されます。結果は、文字列で指定された整数値を表すIntegerオブジェクトです。

に相当

new Integer(Integer.parseInt(s, radix))

radix-sの解釈に使用される基数

したがってInteger.valueOf()、その中間の整数と等しい場合

-128〜127条件でtrueを返します

以下のために lesser than-128とgreater than127それができますfalse


6

与えられた回答を補足するために、次の点にも注意してください。

public class Test { 
    public static void main(String... args) { 
        Integer a = new Integer(129);
        Integer b = new Integer(129);
        System.out.println(a == b);
    }
}

このコードはまた印刷します: false

ユーザーJayは、受け入れられた回答のコメントで主張しているように、==オブジェクトで演算子を使用するときは注意が必要です。ここでは、両方の参照が同じであるかどうかを確認しています。同じ値。オブジェクトを比較するには、equals 代わりにメソッドを使用する必要があります。

Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));

これは印刷されます: true

あなたは尋ねるかもしれませんが、それではなぜ最初の行が印刷されたのtrueですか?Integer.valueOfメソッドのソースコードを確認すると、次のことがわかります。

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

paramがIntegerCache.low(デフォルトは-128)からIntegerCache.high(実行時に最小値127で計算される事前に割り当てられた(キャッシュされた)オブジェクトが返されます。したがって、127をパラメーターとして使用すると、同じキャッシュされたオブジェクトへの2つの参照が取得されtrue、参照の比較が行われます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.