다음 코드를 보자.

Integer a = 1000;
Integer b = 1000;

System.out.println(a==b);

출력 : false

 

매우 당연하다. a와 b는 값이 같아도 다른 오브젝트이기 때문이다.

 

그럼 다음 코드를 보자.

Integer a = 127;    
Integer b = 127;

System.out.println(a==b);

출력 : true

 

잉? 당연히 출력이 false일 것이라 예상했지만 아니다.

Java의 일부 Wrapper 클래스들은 내부에서 캐시값을 가지고 있다.

 

Integer 클래스 내부 코드를 살펴보자.

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 =
		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() {}
}

private statc으로 IntegerCache 클래스를 가지고 있다.

-128 ~ 127 까지의 오브젝트를 array로 생성해 놓고 있다.

 

high값은 "java.lang.Integer.IntegerCache.high" 세팅으로 수정이 가능하다.

 

그리고 오브젝트를 생성할 때 사용한다.

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

 

그러면 캐싱을 왜 사용할까?

 

Java Language Specification(JLS)의 Boxing Conversion 에서 다음과 같이 나와있다.

 

If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.

위의 문구에서 숫자 -128~127 까지의 reference가 동일하다고 얘기하고 있다. (boolean 포함, character도 0~127)

 

Ideally, boxing a primitive value would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rule above is a pragmatic compromise, requiring that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, the rule disallows any assumptions about the identity of the boxed values on the programmer's part. This allows (but does not require) sharing of some or all of these references. Notice that integer literals of type long are allowed, but not required, to be shared.
This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

 

간단히 요약하면 이상적으로는 모든 primitive 값이 boxing이 되면 같은 reference를 가져야 하지만 실제적으로 이것을 모든 부분에 구현하는것은 어렵기 때문에 그래서 일단 일정 범위에 대해서만 java에서 적용하고 실제 구현에 있어서 프로그래머가 알아서 하라고 하는것이다.

'Java' 카테고리의 다른 글

Arrays.asList는 동적 List가 아니다.  (0) 2020.06.19
[Java] Java에서 Map 관련 Iterate(반복문) 방법  (0) 2016.11.10

+ Recent posts