27 Jun 2023

[Java] 오토 박싱과 오토 언박싱

들어가기 전에

우리가 프로그램 개발할 때 여러 자료형을 많이 사용하게 된다. 보통은 원시 타입인 int, double 등의 자료형을 사용하는데, Generic을 사용하는 컬렉션들(List, Map 등)을 사용할 때는 원시 타입을 사용할 수 없고 Wrapper Class라는 Reference Type를 사용해야 한다.

오토 박싱과 오토 언박싱도 자료형의 타입에 따라 생기는 변환 과정이며 Java가 자동으로 해주는 기능 중 하나로 이에 대해 알아볼 것이다.

자료형의 Primitive Type & Wrapper Class

Primitive Type Wrapper Class(Reference Type)
boolean Boolean
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character

래퍼 클래스(Wrapper Class)는 원시 타입(Primitive Type)의 각 단어의 첫 글자를 대문자로 바꾼 수준으로, 무엇인가 감싸주는 클래스라는 의미로 래퍼(Wrapper) 클래스라고 부른다.

이는 원시 타입을 객체로서 다루기 위해 사용하며, 이를 통해 객체(Object)가 된 래퍼 클래스에는 원시 타입과는 달리 null을 저장할 수 있다.

public class Test {
	public static void main(String[] args) {
		Integer integer1 = null; // 정상
		int int1 = null; // 오류
	}
}

원시 타입과 래퍼 클래스 서로 간 변환 과정을 박싱, 언박싱이라고 하는데, 기본 타입을 박스에 담아 감싸주는 과정과 그 반대를 표현하는 것으로

  • 원시 타입 -> 래퍼 클래스 — 박싱

  • 래퍼 클래스 -> 원시 타입 — 언박싱

이라고 한다.

이를 Java에서 자동으로 해주는 걸 오토 박싱, 오토 언박싱 이라고 부른다.

intInteger

박싱과 언박싱

그럼 박싱과 언박싱이 왜 필요한가?

자바에서는 Generic이 래퍼 클래스를 사용하기 때문이다.

Generic은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법인데,

ArrayList<String>이라면 런타임 환경에서 값을 검색할 때 ArrayList<Object>에서 String으로 캐스팅되어 검색되는 것이기 때문이다.

int등의 원시 타입은 최고 조상 클래스인 Object 클래스를 상속받지 않고 있어서 사용할 수 없다.

우리가 사용하는 List<Integer> 등이 예시가 있다. < > 안에 int, double 등의 원시 타입을 쓴다면 **레퍼런스 타입을 사용해야 합니다 **라는 오류가 나게 된다.

이 때문에 래퍼 클래스를 사용하는데, 앞서 말한 List<Integer>의 경우를 생각해보자.

import java.util.ArrayList;
import java.util.List;

public class Test {
	public static void main(String[] args) {
		List<Integer> integerList = new ArrayList<>();
		List<Character> characterList = new ArrayList<>();
		integerList.add(1);
		characterList.add('c');
		
		System.out.println(integerList.get(0).getClass().getName());
		System.out.println(characterList.get(0).getClass().getName());
	}
}

위의 코드에서 결과는

java.lang.Integer
java.lang.Character

처럼 나오게 된다. 리스트에는 1과 c라는 원시 타입으로 넣었는데 우리가 모르는 사이에 자동으로 오토 박싱이 되었던 것이다.

명시적으로도 가능한가?

public class Test {
	public static void main(String[] args) {
		Integer integer1 = 1;
		int integer_to_int1 = integer1.intValue(); // 명시적 언박싱
		
		Integer integer2 = 2;
		int integer_to_int2 = integer2; // 오토 언박싱

		System.out.println(integer_to_int1);
		System.out.println(integer_to_int2);
		
		System.out.println("=======================");
		
		int int1 = 1;
		Integer int_to_integer1 = new Integer(int1); // 명시적 박싱
		
		int int2 = 2;
		Integer int_to_integer2 = int2; // 오토 박싱

		System.out.println(int_to_integer1);
		System.out.println(int_to_integer2);
	}
}

명시적으로 오토 박싱, 오토 언박싱이 가능한데 Java에서 자동으로 해주니 굳이 할 필요는 없을 것 같다.

그냥 래퍼 클래스만 사용하는 건?

기본 타입은 null을 다루지도 못하고, Generic에 담기지도 않는다. 그치만 두 가지의 이점이 있어서 사용하게 된다.

  1. 성능’ 에 대한 이점

원시 타입은 스택 메모리에 값이 존재하지만, 참조 타입인 래퍼 클래스는 힙 메모리에 값이 존재하게 되므로 성능이 낮아진다. 또한 값을 필요로 할 때마다 언박싱 과정을 거쳐야 한다.

plot benchmark primitive wrapper

  1. 점유하는 메모리’ 에 대한 이점

64비트 컴퓨터 기준 점유 메모리이다.

원시타입이 사용하는 메모리 참조타입이 사용하는 메모리
boolean - 1bit Boolean – 128 bits
byte - 8bits Byte - 128bits
short, char - 16bits Short, Charater - 128bits
int, float - 32bits Integer, Float - 128bits
long, double - 64bits Long, Double - 196bits

Primitive Type 과 Wrapper Class의 값 비교

public class Test {
	public static void main(String[] args) {
		Integer integer1 = new Integer(2);
		int int1 = 1;

		System.out.println(integer1 == int1);
	}
}

비교 대상 중 primitive type(int) 의 변수가 하나라도 있다면, == 연산자는 값으로 비교한다.

Boxed primitive 또는 Wrapper class(Integer) 끼리 비교 하는 경우, == 연산자는 각 객체의 주소 값을 비교 하게 된다. 값끼리의 비교는 equal 메소드를 사용해야한다.

정리

  1. Primitive Type -> Reference Type를 박싱이라고 하며,

  2. Reference Type -> Primitive Type를 언박싱이라고 한다.

  3. 이를 Java에서 자동으로 해주는 것을 오토 박싱, 오토 언박싱이라고 일컫는다.
  4. 성능과 메모리에 장점이 있는 Primitive Type을 먼저 고려하고, 만약 null 사용 또는 Generic 타입에서 사용되어야 한다면 Wrapper Class를 사용한다.

참고자료

http://www.tcpschool.com/java/java_api_wrapper

https://siyoon210.tistory.com/139

https://velog.io/@kimmjieun/Java-Integer-int-%EC%88%AB%EC%9E%90-%EB%B9%84%EA%B5%90-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD

https://www.geeksforgeeks.org/why-java-collections-cannot-directly-store-primitives-types/

https://stackoverflow.com/questions/1040384/why-do-some-languages-need-boxing-and-unboxing

Thank You For Reading
SeungJun Jeon

점점 강해지고 있습니다.

comments powered by Disqus