int vs Integer
자료구조 공부를 하던 초기에 이런 일을 겪은 적이 있었다. 정수형 리스트를 int[]로 변환하고 싶었다.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0); // 0 추가
int[] arr = list.toArray(new int[1]); // 오류 발생
그랬더니 마지막 줄에서 다음과 같은 오류가 발생했다.
The method toArray(T[]) in the type ArrayList<Integer> is not applicable for the arguments (int[])
ArrayList.toArray() 메서드는 ArrayList<Integer>를 int[]로 바꿀 수 없다는 내용이었다.
당시에는 같은 정수형인데 왜 바꿔주지 않는지 이해가 가지 않았다. 하지만 곰곰이 생각해보니
int와 Integer가 "차이가 없다면 왜 다르게 써왔을까?" 라는 의문이 들었다. int는 변수를 선언할 때, Integer는 자료구조의 객체를 정할 때 쓴다고 생각하고 별 생각 없이 사용해왔던 것 같다.
기본형과 참조형
돌이켜보면 처음 개발 공부를 시작했을 때, int는 주황색이고 소문자로 시작하지만 String은 파란색에 대문자로 시작하는 것에 딱히 의문을 갖지 않았다. 늘 변수를 선언할때 사용했던 것들이지만 근본적으로 다른 것이다.
자바의 값의 타입은 기본형(primitive type)과 참조형(reference type)의 두 가지가 있다.
여기서 int는 정수의 기본형, Integer는 참조형이다.
자바에서 기본형은 딱 8가지가 있다.
정수(byte, short, int, long), 논리(boolean), 문자(char), 실수(float, double)이다.
이를 제외한 나머지 타입은 전부 참조형이다. 참조형은 사용자가 맘대로 생성할 수 있다.
기본형(primitive type)의 특징
- byte, short, int, long, boolean, char, float, double 총 8가지이며, 각 메모리 크기는 다르다.
- 선언과 동시에 메모리가 할당된다.
- 모든 값은 스택(stack)에 저장된다.
- 저장공간에 실제 값이 저장된다.
- Null 값을 가질 수 없다.
참조형(reference type)의 특징
- 위의 기본형 8개를 제외한 모든 타입에 해당된다.
- 실제 값은 힙(heap)에 저장되며, 스택(stack)에는 그 주솟값을 저장한다.
- Null 값을 가질 수 있다.
둘은 어떻게 사용할까?
int와 Integer는 같은 정수에 관한 변수이지만 다룰 때 차이점이 존재한다.
[선언]
int intA = 3;
Integer integerA = new Integer(3);
int는 바로 변수명 이후 값을 초기화하면 되지만, Integer는 "원칙적으로" 인스턴스 생성과 동일하게 생성자를 통해 선언해야 한다.
[int <-> Integer 변환]
intA = integerA.intValue(); // 언박싱
integerA = Integer.valueOf(intA); // 박싱
Integer는 int의 Wrapper Class이다.
Wrapper Class는 기본형 변수를 객체처럼 취급하여 사용할 때 필요하다. Wrapper Class는 참조형이며, 이를 통해 매개변수에 객체로서 들어가거나, 메서드를 사용할 수 있다.
이때 int -> Integer를 Boxing, Integer -> int를 UnBoxing이라고 한다.
따라서 int와 Integer는 "원칙적으로" 변환할 때마다 Integer.valueOf()와 Integer.intValue()를 이용해야 한다.
"원칙적으로?" - 자동 박싱과 언박싱
int와 Integer를 오가려면 원칙적으로는 박싱과 언박싱 과정을 계속 거쳐야 한다. 하지만 워낙에 많이 이용하는 데이터 타입이라 그런지, JDK 1.5부터는 오토 박싱과 오토 언박싱을 지원하기 시작했다.
int a = 5;
Integer b = new Integer(5);
System.out.println(a == b); // true
a = b;
b = a;
Integer c = 5;
위와 같이 int가 Integer를, Integer이 int를 가리킬 수 있으며 a == b도 true를 반환한다.
또한 Integer 선언도 int형처럼 할 수 있다. 이러한 자동 박싱은 메서드에서도 나타난다.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(Integer.valueOf(3));
list.add(3);
int a = list.get(0).intValue();
int a = list.get(0);
위의 list는 Integer형이므로 원칙적으로는 int형인 3이 들어가면 에러가 발생해야 한다. 따라서 Integer.valueOf(3)으로 박싱을 해서 넣어야 맞지만, int형인 3을 넣어도 컴파일러가 자동으로 Integer.valueOf(3)으로 코드를 변경해준다.
또한 list.get(0)은 Integer형이므로 변수 a에 넣을 수 없다. 그래서 list.get(0).intValue() 처럼 int형으로 변환을 해야 하지만 list.get(0)만 해도 알아서 언박싱을 해준다.