はじめに
この記事では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以上にすることができます
参考文献
Views: 0