ボクシングとキャッシュ
Integerのキャッシュ
int がボクシングされると java.lang.Integer になりますが、このとき Integer.valueOf(int) が使われます。
このことは次のようなボクシングされるコードを書いてコンパイルしてからjavapすればよく分かります。
public class IntBoxingSample {
public Integer boxing(int i) {
return i;
}
}
javapしてみた結果は次の通り。
Compiled from "IntBoxingSample.java"
public class IntBoxingSample {
public IntBoxingSample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.Integer boxing(int);
Code:
0: iload_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: areturn
}
で、この Integer.valueOf(int) ですが、 -128 から 127 までの範囲はキャッシュされます。
このことは言語仕様の5.1.7やInteger.valueOf(int)のJavadocに書かれています。
でもって、OpenJDKのコードを見た感じ、java.lang.Integer.IntegerCache.highというシステムプロパティでキャッシュする範囲を変更できそうです。
というわけで次のようなコードを書いてコンパイルして普通に実行すると false と表示されますが、 -Djava.lang.Integer.IntegerCache.high=1000 という風にシステムプロパティを設定して実行すると true と表示されます。
public class Sample {
public static void main(String[] args) {
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);
}
}
実行結果は次の通り。
% java Sample
false
% java -Djava.lang.Integer.IntegerCache.high=1000 Sample
true
他のプリミティブも見てみた
Byte 、 Short 、 Long は Integer と同じく -128 から 127 までキャッシュされていました。 ただしキャッシュの範囲は変更できません。
- Byte.valueOf(byte)のコードとByteのキャッシュ構築コード
- Short.valueOf(short)のコードとShortのキャッシュ構築コード
- Long.valueOf(long)のコードとLongのキャッシュ構築コード
それから Character は 0 から 127 までキャッシュされていました。
ASCII文字コードの NUL から DEL ですね。
Boolean は定数 TRUE と FALSE のどちらかを返すようになっています。
最後に Float と Double ですが、どちらもキャッシュせず常にインスタンス化するようになっていました。
浮動小数点数なので -128.0 から 127.0 の間にも膨大な量のインスタンスを生成し得るので、まあ、そりゃキャッシュしないか、という感じ。
まとめ
以上のように普段は意識しないような部分でキャッシュしておりパフォーマンス向上を図っていたりしています。
こういったJDKの努力に感謝しつつ、今後も意識せずにコーディングしようと思います。
Discussion