60

キャシー・シエラとバート・ベイツのSCJP Java 6を読んでいますが、この本は私をとても混乱させています。245ページに、次のコードが記載されています。

Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2)
System.out.println("different objects");

//Prints output
different objects

次に、次のページに次のコードがあります

Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
System.out.println("same objects");

//Prints output
same objects

私は困惑している!これを自分で試してみると、equals()メソッドを使用するのと同じ方法で==を使用して比較することはできないようです。==を使用すると、整数変数が同じ値(つまり、10)に設定されている場合でも、常に「false」が返されます。私は正しいですか?==を使用して同じ整数オブジェクト(同じ値)を比較すると、常に「false」になります

4

8 に答える 8

70

答えの鍵はオブジェクトインターンと呼ばれます。Javaは少数(128未満)をインターンするため、インターンされた範囲内のInteger(n)withのすべてのインスタンスnは同じです。128以上の数はインターンされないため、Integer(1000)オブジェクトは互いに等しくありません。

于 2012-04-14T00:32:28.203 に答える
20

ソースコードを見ると、 -128から127までのすべての値がプールIntegerされていることがわかります。その理由は、小さな整数値が頻繁に使用されるため、プール/キャッシュする価値があるためです。Integer.valueOf(int)

からまっすぐに取られたInteger.java

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

このプーリングは実装固有であり、プールされた範囲の保証はないことに注意してください。

インターンについての答えは、概念的には正しいですが、用語では正しくありません。Javaでのインターンは通常、Javaランタイムがプーリング(Stringのインターンなど)を実行していることを意味します。Integerの場合、プーリングを実行しているのはクラス自体です。JVMの魔法は関係していません。

于 2012-04-14T00:57:37.503 に答える
8

インターンについての上記の答えは正しいです。ただし、考慮すべき点は次のとおりです。

Integer i3 = new Integer(10);
Integer i4 = new Integer(10);

新しいオブジェクトを明示的に作成したため、新しいオブジェクトはありません。次のようにコードを書くと、インターンされます。

Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);

これらは再び同じオブジェクトになります。src.zipファイルのInteger.javaクラス内のvalueOfメソッドを見ると、intの値が-128から127の範囲外であるかどうかを確認する場所がわかります。そうでない場合は、新しいIntegerクラスが呼び出されます。キャッシュからロードします。

于 2012-04-14T00:43:37.997 に答える
3
Integer i1 = 1000;
Integer i2 = 1000;

コンパイラは、int1000を整数オブジェクトとして「ボックス化」します。これを行うために、ソースを次のように変換します。

Integer i1 = Integer.valueOf(1000);
Integer i2 = Integer.valueOf(1000);

valueOfこれは単純な呼び出しである可能性がありますが、ボックス化さnew Integer(1000)れるたびに新しいIntegerオブジェクトを作成すると、時間とスペースの両方が必要になります。intこれを回避するために、Integerクラスは限られた範囲のint値のIntegerオブジェクトの配列を保持します。

if(value> maxRange || value< minRange){
     //not in pool return new Integer
     return new Integer(value);
}else{
     //return pooled Integer object
     //for the value, pool contains all Integer
     //values from minRange to maxRange
     return integerPool[value-minRange];
}

これにより得られる速度と失われるメモリは、プログラムの開始時にjvm引数を使用して範囲を設定することで調整できます(デフォルトでは-127〜128に設定されています)。

于 2012-04-16T19:22:51.273 に答える
0

Java ==演算子を使用してプリミティブ型以外のものを比較する場合、参照が等しいかどうかをチェックします。これは、比較対象がラップされたプリミティブである場合でも適用されます。さらに、valueOfメソッドとコンパイラによって生成されたオートボクシングステートメントは、通常、他の既存の参照と同等ではない新しいオブジェクトを任意に返すか、既存のオブジェクトへの参照を返すことができます(もちろん、参照である-同じオブジェクトを識別する既存の参照と同じ)。Integer実装は、値-128〜127のインスタンスの「プール」を維持する必要があります。これにより、Integer.valueOfその範囲内の特定の番号では、同じオブジェクトへの参照が返されますが、それ以外の場合、実装は次のようなことを自由に行うことができます。

static Integer [] intPool = new Integer[256];

public Integer valueOf(int n)
{
  int hash = (n*0x18675309) >>> 24;
  Integer instance = intPool[n];
  if (instance == null && instance.value != n)
  {
    instance = new Integer(n);
    intPool[hash] = instance ;
  }
  return instance;
}

多くの場合、「キャッシュヒット」率は0%に近く、キャッシュ内のインスタンスの検索に費やされる余分な時間が無駄になるため、Java実装がそのようなことをすることは特に期待していません。それにもかかわらず、によって返される参照がそのメソッドによって返される以前の参照と一致しないという保証はありません(そのメソッドによって返される最後のinstanceOf参照と一致しない場合でも、一部のキャッシュアルゴリズムにより、以前の参照が返される可能性があります特にプールがロックせずに複数のスレッドで共有されている場合は、参照してください。ロックがないため、コードが正しい値の整数への参照以外のものを返すことはありませんが、返される参照が等しくなるという予測できない変動が発生する可能性があります。Integerコンストラクターを使用して直接作成されたオブジェクトへの参照のみnew Integer(n)が一意であることが保証されます。valueOfによって返される参照が、によって返される参照と一致しないことを期待するコードはvalueOf、実際に一致しないことを確認せずに、壊れていると見なす必要があります。

于 2013-11-23T18:06:10.023 に答える
0

==と!=を使用した文字列比較と整数比較では、期待どおりのブール結果が得られません。したがって、未知の結果がソフトウェアのパフォーマンス、信頼性、精度を妨げないように注意してください。

于 2014-01-07T17:11:52.457 に答える
0

"=="は、常に値のメモリ位置またはオブジェクト参照を比較します。equalsメソッドは常に値を比較しますが、equalsは間接的に「==」演算子を使用して値を比較します。Integerは、整数キャッシュを使用して-128〜 + 127の値を格納します。==演算子を使用して-128〜127の値をチェックすると、trueが返されます。-128〜127の値の場合

Integer i1 = -128; 
Integer i2 = -128; 
System.out.println(i1 == i2); // returns true

上記の範囲以外の場合はfalseを返します

Integer i1 = 1000;
Integer i2 = 1000;
System.out.println(i1 == i2); // returns false

追加情報については、リンクを参照してください

于 2016-08-01T17:12:12.790 に答える
0

jls-5.1.7によると

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f,   
or an int or short number between -128 and 127 (inclusive), then let r1 and r2 
be the results of any two boxing conversions of p. It is always the case that r1 == r2.

したがって、-128〜127の数値は、Intergerクラスによってキャッシュされます。 2つのオブジェクトを比較するときは、常にメソッドを使用することを忘れないでください。
equals

キャッシングコードは、IntegerCacheクラスのメンバーであるクラスで記述されIntegerます。

コードスニペットは次のとおりです。

 /**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

参考文献

于 2018-06-12T10:18:32.660 に答える