JavaのIntegerCacheについて

java.lang.Integer.valueOf(int)の実装は

    public static Integer valueOf(int i) {
	final int offset = 128;
	if (i >= -128 && i <= 127) { // must cache 
	    return IntegerCache.cache[i + offset];
	}
        return new Integer(i);
    }

SE5以降上のようになっているので,ここに書いてあるようにboxingしたときに参照比較の結果が変わってくる.

仕様だとintをIntegerにboxingしたときの結果についてはpがint型の時,変換の結果のInteger型rについてはp==r.intValue()をみたすものなら何でもいいので,この結果は実装依存である.

こういうキャッシュすることによって,何が嬉しいかというとインスタンスを生成する手間が省けるのでメモリと実行時間が節約できる.(cf: Flyweight pattern - Wikipedia)

実際に試したところ

import java.util.*;

public class Test {
	static long test(int val){
		List<Integer> lst = new LinkedList<Integer>();
		long time = System.currentTimeMillis();
		for(int i=0;i<100000;i++){
			lst.add(val);
		}
	    time = System.currentTimeMillis() - time;
		return time;
	}
	static long test2(int val){
		List<Integer> lst = new LinkedList<Integer>();
		long time = System.currentTimeMillis();
		for(int i=0;i<100000;i++){
			lst.add(new Integer(val));
		}
	    time = System.currentTimeMillis() - time;
		return time;
	}

	public static void main(String[] args) {
		long t100 = 0;
		long t200 = 0;
		for(int i=0;i<100;i++){
			t100 += test(100);
			t200 += test(200);			
		}
		System.out.println("test(100)*100 = " + t100 + "ms");
		System.out.println("test(200)*100 = " + t200 + "ms");
		t100 = 0;
		t200 = 0;
		for(int i=0;i<100;i++){
			t100 += test2(100);
			t200 += test2(200);			
		}
		System.out.println("test2(100)*100 = " + t100 + "ms");
		System.out.println("test2(200)*100 = " + t200 + "ms");
	}
}

実行結果

test(100)*100 = 5626ms
test(200)*100 = 8999ms
test2(100)*100 = 9014ms
test2(200)*100 = 9064ms

でキャッシュがきいていることがわかる.