7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Java】なぜIntegerは-128から127で == がtrueになるのか

Posted at

はじめに

この記事ではJavaのIntegerにおいて特定の範囲において必ずtrueになるのがなぜなのかを解説します。

なぜオブジェクトの比較に == を使うのがダメなの?

これは == が同じメモリ位置を参照しているかどうかを比較しているのに対し、 equals() がオブジェクトの中身を比較していることが理由となります。
この事から、Integerはintのラッパークラス(オブジェクト)なので、equals()を使うべきだと言えます。

本題

本来なら equals() を使うのでこの問題はそこまで出てこないと思いますが、
実は -128から127 の範囲でIntegerの比較を行う場合に等価であると判定されます。

public class Main {
    public static void main(String[] args) {
        Integer numberA = 127;
        Integer numberB = 127;
        
        System.out.println(numberA == numberB); // true
        
        Integer numberC = 128;
        Integer numberD = 128;
        
        System.out.println(numberC == numberD); // false
    }
}

なぜ-127から128だと == がtrueになるのか

Java5から IntegerCache と呼ばれる、キャッシュを利用することでInteger型の処理を向上させる機能が導入されました。
これは特定の範囲の整数値において、同じオブジェクトを再利用するというもので、
特定の範囲の整数値というのが -128から127 になります。

IntegerCacheの実装は以下より確認することができます。
https://github.com/openjdk/jdk/blob/jdk-26%2B3/src/java.base/share/classes/java/lang/Integer.java#L915-L985

private static final class IntegerCache {
    static final int low = -128;
    static final int high;

    @Stable
    static final Integer[] cache;
    static Integer[] archivedCache;

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

        // Load IntegerCache.archivedCache from archive, if possible
        CDS.initializeFromArchive(IntegerCache.class);
        int size = (high - low) + 1;

        // Use the archived cache if it exists and is large enough
        if (archivedCache == null || size > archivedCache.length) {
            Integer[] c = new Integer[size];
            int j = low;
            // If archive has Integer cache, we must use all instances from it.
            // Otherwise, the identity checks between archived Integers and
            // runtime-cached Integers would fail.
            int archivedSize = (archivedCache == null) ? 0 : archivedCache.length;
            for (int i = 0; i < archivedSize; i++) {
                c[i] = archivedCache[i];
                assert j == archivedCache[i];
                j++;
            }
            // Fill the rest of the cache.
            for (int i = archivedSize; i < size; i++) {
                c[i] = new Integer(j++);
            }
            archivedCache = c;
        }
        cache = archivedCache;
        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

範囲を決定している箇所

static final int low = -128;
static final int high;

@Stable
static final Integer[] cache;
static Integer[] archivedCache;

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

IntegerCacheの範囲は $[\mathrm{low}, \mathrm{high}]$ であり、$\mathrm{low} = -128$、$\mathrm{high} = 127$であることがわかります。
この値範囲は JLS5.1.7. Boxing Conversion で定義されています。

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.

補足
オプションとして、java.lang.Integer.IntegerCache.high の値を128以上にすることで、上限値を127以上にする事が可能になります。

まとめ

  • IntegerにおいてはJava5から導入されたIntegerCacheによって-128から127の範囲においてオブジェクトがキャッシュされる影響で == がtrueになることを解説しました
  • IntegerCacheの実装によると、上限値は java.lang.Integer.IntegerCache.high を変更することで128以上にすることができます

参考文献

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?