자바/자바기초

[자바] 7화 박싱(Boxing) & 언박싱(Unboxing)과 사용 이유

khao 2016. 5. 17. 00:45

이번 시간은 매우 짧게 끝날 것 같습니다. 하지만 박싱과 언박싱을 하며 자바가 다른 언어보다 느린 이유를 알게 되는 시간이기 때문에 의미만큼은 클 것이라 생각됩니다. (초를 치자면, JVM에서 실행되는 것이 크긴 합니다.)

자바에서 모든 객체는 힙(HEAP)영역에 저장됩니다. 또한 int나 char, float같은 변수들은 클래스 변수로 선언되어 인스턴스 안에 포함되거나 static으로 선언되지 않았다면 모두 스택(STACK)영역에 저장됩니다. 오늘은 어떤 것이 어떤 영역에 저장되는지 먼저 알고 시작해야 정확한 이해를 할 수 있습니다.


[위가 박싱, 아래가 언박싱에 대한 그림]

(1.5버전부터 래퍼클래스와 primitive type이 같으면 형변환 같은 것을 하지 않아도 된다.) 


우선 박싱(Boxing)과 언박싱(Unboxing)에 대해 설명하자면, 박싱은 int나 float같은 값을 객체 안에 넣어주는 일이고, 언박싱은 이렇게 넣었던 int나 float값을 다시 빼내는 일을 뜻합니다. 그리고 이 박싱을 지원해주는 Integer나 Float같은 클래스들을 무엇인가를 감싸준다는 의미에서 래퍼(wrapper)클래스라고 합니다.


이제 이론적으로는 박싱이 무슨 작업이고 언박싱이 무슨 작업인지에 대해 알았습니다. 그렇다면 우리는 왜 박싱을 해야 하고 언박싱을 해야할까요?


자바에서는 래퍼클래스(Integer, Float)과 기본자료형(primitive type이라 하며 int, float같은 것을 의미함.)이 있는데 이후에 할 제네릭 부분에서 제네릭은 primitive type을 받지 않습니다. 그렇기 때문에 래퍼클래스를 이용하여 제네릭을 사용할 수 밖에 없으므로 박싱을 사용한다고 생각하시면 됩니다. (개인적으로 제네릭 외에는 '이것 때문에 꼭 써야 한다'는 부분은 없는 것 같습니다.)


이렇게 박싱, 언박싱을 써서 자료형을 표현할 수 있다면 우리는 왜 primitive type을 써야할까요? 이는 단순값만을 가진 객체를 굳이 사용할 필요가 없기 때문입니다. 자바는 모든 객체를 힙에 저장합니다. 그런데 이 힙이란 것이 상대적으로 스택에서 불러올 때보다 속도가 떨어집니다. 속도를 버려가면서 primitive type으로 표현해도 문제되지 않는 부분까지 일부러 래퍼클래스로 만드는 것은 불필요하기 때문에 래퍼클래스만을 활용하지 않는 것입니다. (물론 몇 개 래퍼클래스로 한다고 해서 확 느려지는 것도 아니긴 합니다.)


public class TimeTest {
	public static void main(String[] args) {
		long start = 0;
		long end = 0;
 
		//primitive type
		start = System.currentTimeMillis();
		fibonacci1(30);
		end = System.currentTimeMillis();
		System.out.println("int를 이용한 피보나치 연산::" + (end - start));
 
 
		//Wrapper Class
		start = System.currentTimeMillis();
		fibonacci2(30);
		end = System.currentTimeMillis();
		System.out.println("Integer를 이용한 피보나치 연산::" + (end - start));
	}
 
	public static int fibonacci1(int value) {
		if (value == 0 || value == 1)
			return 1;
		else
			return fibonacci1(value - 1) + fibonacci1(value - 2);
	}
 
	public static Integer fibonacci2(int value) {
		if (value == 0 || value == 1)
			return 1;
		else
			return fibonacci2(value - 1) + fibonacci2(value - 2);
	}
}


이 소스코드를 돌려보면 항상 STACK보다 HEAP에서 더 느리다는 것을 알 수 있습니다.

제 컴퓨터의 경우에는 최소 2.5배에서 많으면 4배까지 차이가 나네요.

(이론상으로의 최대치는 이보다 더 큰 것으로 알고 있습니다.)


소스코드 결과를 통해 래퍼클래스는 필요할 때만 쓰는 것이 효율적임을 알 수 있습니다.