129

次のようなコードを見ました。

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

実行すると、このコード ブロックが出力されます。

false
true

最初の理由がわかりfalseました。2 つのオブジェクトが別々のオブジェクトであるため、==参照が比較されます。しかし、私は理解できません.2番目のステートメントが返されるのはなぜtrueですか? 整数の値が特定の範囲にあるときに作動する奇妙なオートボクシング ルールはありますか? 何が起きてる?

4

12 に答える 12

116

このtrue行は実際には言語仕様によって保証されています。セクション 5.1.7から:

ボックス化される値 p が true、false、バイト、\u0000 ~ \u007f の範囲の char、または -128 ~ 127 の int または short の数値である場合、r1 と r2 は任意の 2 つのボックス化変換の結果とします。 pの。r1 == r2 は常にそうです。

議論は続き、出力の 2 行目は保証されていますが、最初の行は保証されていないことを示唆しています (以下に引用されている最後の段落を参照してください)。

理想的には、指定されたプリミティブ値 p をボックス化すると、常に同一の参照が生成されます。実際には、これは既存の実装技術を使用して実現できない場合があります。上記のルールは実用的な妥協案です。上記の最後の節では、特定の共通値を常に区別できないオブジェクトにボックス化する必要があります。実装は、遅延または積極的にこれらをキャッシュする場合があります。

他の値については、この定式化により、プログラマー側でボックス化された値の同一性に関する仮定ができなくなります。これにより、これらの参照の一部またはすべてを共有できます (必要ではありません)。

これにより、ほとんどの一般的なケースで、特に小さなデバイスで過度のパフォーマンスのペナルティを課すことなく、動作が目的の動作になることが保証されます。メモリ制限の少ない実装では、たとえば、-32K ~ +32K の範囲の整数と長整数だけでなく、すべての文字と短整数をキャッシュする場合があります。

于 2010-06-28T05:57:45.547 に答える
38
public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

出力:

false
true

はい、参照を比較するために最初の出力が生成されます。'a' と 'b' - これらは 2 つの異なる参照です。ポイント1では、実際には次のような2つの参照が作成されます-

Integer a = new Integer(1000);
Integer b = new Integer(1000);

2 番目の出力は、 が範囲内 (-128 ~ 127) にあるJVMときにメモリを節約しようとするために生成されます。Integerポイント 2 では、'd' に対して Integer 型の新しい参照は作成されません。整数型参照変数「d」の新しいオブジェクトを作成する代わりに、「c」によって参照される以前に作成されたオブジェクトのみが割り当てられます。これらはすべて によって行われJVMます。

これらのメモリ節約ルールは、Integer だけのものではありません。メモリ節約の目的で、次のラッパー オブジェクトの 2 つのインスタンス (ボクシングによって作成されている間) は、常に == であり、プリミティブ値は同じです -

  • ブール値
  • バイト
  • \u0000から\u007f(7f は 10 進数で 127)までの文字
  • -128127の Short および Integer
于 2014-04-05T05:32:16.930 に答える
10

ある範囲(おそらく-128から127だと思います)の整数オブジェクトはキャッシュされ、再利用されます。その範囲外の整数は、毎回新しいオブジェクトを取得します。

于 2010-06-28T05:46:17.927 に答える
6

はい、値が特定の範囲内にあるときに作動する奇妙な自動ボクシング ルールがあります。オブジェクト変数に定数を代入する場合、言語定義には、新しいオブジェクトを作成する必要があるとは書かれていません。キャッシュから既存のオブジェクトを再利用する場合があります。

実際、JVM は通常、この目的のために小さな整数のキャッシュと、Boolean.TRUE や Boolean.FALSE などの値を格納します。

于 2010-06-28T05:46:54.117 に答える
4

それは興味深い点です。本の中でEffective Javaは、独自のクラスのequalsを常にオーバーライドすることを提案しています。また、Java クラスの 2 つのオブジェクト インスタンスが等しいかどうかを確認するには、常に equals メソッドを使用します。

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

戻り値:

true
true
于 2013-06-17T14:13:02.797 に答える
4

私の推測では、Java は既に「ボックス化」されている小さな整数のキャッシュを保持していると思います。それらは非常に一般的であり、新しいオブジェクトを作成するよりも既存のオブジェクトを再利用する方が多くの時間を節約できるからです。

于 2010-06-28T05:46:26.710 に答える
3

Java では、ボクシングは整数の -128 から 127 の範囲で機能します。この範囲の数値を使用している場合は、== 演算子で比較できます。範囲外の整数オブジェクトの場合、等号を使用する必要があります。

于 2010-06-28T06:19:41.163 に答える
1

クラスのソース コードを確認すると、次のようIntegerにメソッドのソースを見つけることができます。valueOf

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

Integerこれは、-128 ( Integer.low) から 127 ( Integer.high) の範囲にあるオブジェクトが、オートボクシング中に同じ参照オブジェクトである理由を説明しています。そして、クラスのプライベート静的内部クラスであるキャッシュ配列を処理IntegerCacheするクラスがあることがわかります。IntegerInteger

この奇妙な状況を理解するのに役立つ別の興味深い例があります。

public static void main(String[] args) throws ReflectiveOperationException {
    Class cache = Integer.class.getDeclaredClasses()[0];
    Field myCache = cache.getDeclaredField("cache");
    myCache.setAccessible(true);

    Integer[] newCache = (Integer[]) myCache.get(cache);
    newCache[132] = newCache[133];

    Integer a = 2;
    Integer b = a + a;
    System.out.printf("%d + %d = %d", a, a, b); // The output is: 2 + 2 = 5
}
于 2016-11-17T06:11:22.290 に答える
0

Java 5 では、メモリーを節約し、整数型オブジェクト処理のパフォーマンスを向上させるための新しい機能が導入されました。整数オブジェクトは内部的にキャッシュされ、同じ参照オブジェクトを介して再利用されます。

  1. これは、–127 ~ +127 (最大整数値) の範囲の整数値に適用されます。

  2. この整数キャッシングは、オートボクシングでのみ機能します。整数オブジェクトは、コンストラクターを使用して構築されたときにキャッシュされません。

詳細については、以下のリンクを参照してください。

整数キャッシュの詳細

于 2016-06-02T14:15:48.110 に答える