컴파일러가 primitive 타입을 wrapper 클래스 타입으로 변환해주는 것을 autoboxing이라고 합니다. 예를 들어 int타입을 Integer로, double을 Double로 바꾸는 경우입니다. 아래는 autoboxing이 발생하는 경우를 예시로 든 것입니다.
1
2
3
4
5
6
7
Integer sum = 0; // int -> Integer
Character c = 'a'; // char -> Character
List<Integer> li = new ArrayList<>();
for (int i = 0; i < 10; i++)
li.add(i); // i가 int -> Integer
sum += i; // i가 int -> Integer
숫자, 문자 등의 리터럴은 primitive type입니다. 이를 Wrapper Class인 Integer나 Character에 담으려하면 autoboxing이 발생합니다. Integer 타입인 리스트에 int 타입의 정수를 추가하려해도 autoboxing이 발생합니다.
구체적으로 아래의 2가지 경우에 autoboxing이 발생합니다.
- 메서드 매개변수의 타입이 wrapper class이지만, 넘어온 값이 primitive type일 때.
- wrapper class의 변수에 primitive type을 할당할 때.
이처럼 primitive -> wrapper class으로 변환이 필요한 경우에는 컴파일 타임에 컴파일러가 변환해줍니다. 실제 컴파일된 이후에는 아래와 같이 valueOf 등의 변환 함수로 대체됩니다.
1
2
3
4
5
// compile 전
li.add(123);
// compile 후
li.add(Integer.valueOf(123)); // valueOf로 변환.
autoboxing과는 반대로 wrapper class -> primitive type으로 변환되는 경우도 있습니다. 이 변환을 unboxing이라고 합니다.
1
2
3
4
5
6
7
8
9
// compile 전
for (Integer i: li)
if (i % 2 == 0)
sum += i;
// compile 후
for (Integer i : li)
if (i.intValue() % 2 == 0) // intValue()가 추가 됨.
sum += i.intValue(); // intValue()가 추가 됨.
이렇게 wrapper class를 마치 int처럼 사용할 수 있습니다. class임에도 각종 연산자를 붙일 수 있고, primitive type의 변수에 값을 바로 대입할 수도 있습니다. 물론 실제로는 컴파일러가 primitive type으로 변환하는 것이지만요.
autoboxing과 unboxing은 상당히 편리한 기능입니다. 하지만 비교적 성능이 느려지는 문제가 있습니다. 그래서 가능한 autoboxing과 unboxing이 발생하지 않도록 하는 편이 좋습니다.
참고
1. https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html