래퍼(wrapper) 클래스와 오토박싱&언박싱
1. 래퍼(wrapper) 클래스
객체지향 개념에서 모든 것은 객체로 다루어져야 한다. 그러나 자바에서는 8개의 기본형을 객체로 다루지 않는데
이것이 바로 자바가 완전한 객체지향 언어가 아니라는 얘기를 듣는 이유이다. 그 대신 보다 높은 성능을 얻을 수 있다.
때로는 기본형(primitive type) 변수도 어쩔 수 없이 객체로 다뤄야 하는 경우가 있다. 예를 들면, 매개변수로 객체를 요구할 때,
기본형 값이 아닌 객체로 저장해야 할 때, 객체간의 비교가 필요할 때 등등의 경우에는 기본형 값들을 객체로 변환하여 작업을
수행해야한다. 이 때 사용되는 것이 래퍼(wrapper)클래스이다. 아래는 8개의 기본형의 래퍼클래스이다.
기본형 | 래퍼클래스 | 생성자 | 활용예 |
boolean | Boolean | Boolean(boolean value) Boolean(String s) |
boolean b = new Boolean(true); boolean b2 = new Boolean("true"); |
char | Characte | Character(char value) | Character c= new Character('a); |
byte | Byte | Byte(byte value) Byte(String s) |
Byte b = new Byte(10); Byte b2 = new Byte("10"); |
short | Short | Short(short value) Short(String s) |
Short s = new Short(10); Short s2 = new Short("10"); |
long | Long | Long(long value) Long(String s) |
Long l = new Long(100); Long l2 = new Long("100"); |
float | Float | Float (double value) Float (float value) Float (String s) |
Float f = new Float(1.0); Float f2 = new Float(1.0f); Float f3 = new Float("1.0f"); |
double | Double | Double(double value) Double(String s) |
Double d = new Double(1.0); Double d = new Double("1.0"); |
래퍼 클래스의 생성자는 매개변수로 문자열이나 각 자료형 값들을 파라미터로 받는다. 이 때 주의해야할 것은 생성자의 매개변수로
문자열을 제공할 때 , 각 자료형에 알맞은 문자을 사용해야한다는 것이다. 예를 들어 'new Integer("1.0")과 같이 하면
NumberFormatException 이 발생한다.
1) 예제
public class Ex9_11 {
public static void main(String args[]){
Integer i = new Integer(100);
Integer i2 = new Integer(100);
System.out.println("i==i2 ? " + (i==i2));
System.out.println("i.eqials(i2) ? " + i.equals(i2));
System.out.println("i.compareTo(i2) =" + i.compareTo(i2));
System.out.println("i.toString()=" + i.toString());
System.out.println("MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println("MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("SIZE= " + Integer.SIZE +" bits");
System.out.println("BYTES=" + Integer.BYTES+" bytes");
System.out.println("TYPE=" + Integer.TYPE);
}
}
i==i2 ? false
i.equals(i2) ? true
i.compareTo(i2) = 0
i.toString() = 100
MAX_VALUE = 2147483647
MIN_VALUE = - 2147483648
SIZE = 32 bits
BYTES = 4 bytes
TYPE = int
래퍼 클래스들은 모두 equals()가 오버라이딩 되어 있어 주소값이 아닌 객체가 가지고 있는 값을 비교한다.
그래서 실행결과를 보면 equals()를 이용한 두 Integer 객체의 비교가 true라는 것을 알 수 있다.
오토박싱이 된다고 해도 Integer객체에 비교연산자를 사용할 수 없고 대신 compareTo()를 제공한다.
그리고 toString()도 오버라이딩이 되어 있어 객체가 가지고 있는 값을 문자열로 변환하여 반환한다.
이 외에도 래퍼 클래스들은 MAX_VALUE, MIN_VALUE, SIZE, BYTES, TYPE 등의 static 상수를 공통적으로 가지고 있다.
2. 오토박싱 & 언박싱
JDK 1.5 이전에는 기본형과 참조형간의 연산이 불가능했기 때문에, 래퍼 클래스로 기본형을 객체로 만들어서 연산해야 했다.
int i = 5;
Integer iObjs = new integer(7);
int sum = i + iObj; // 에러. 기본형과 참조형 간의 덧셈 불가 (JDK1.5 이전)
그러나 이제는 기본형과 참조형 간의 덧셈이 가능하다. 컴파일러가 자동으로 변환하는 코드를 넣어주기 때문이다.
아래의 경우, 컴파일러가 Integer객체를 int 타입의 값으로 변환해주는 intValue()를 추가해준다.
컴파일 전의 코드 | 컴파일 후의 코드 |
int i = 5; Integer iObj = new Integer(7); int sum = i + iObj; |
int i =5; Integer iObj = new Integer(7); int sum = i + iObj.intValue(); |
이 외에도 내부적으로 객체 배열을 가지고 있는 Vector 클래스나 ArrayList클래스에 기본형 값을 저장해야 할 때나 형변환이
필요할 때도 컴파일러가 자동적으로 코드를 추가해준다. 기본형 값을 래퍼클래스의 객체로 자동 변환해주는 것을
'오토박싱(autoboxing)'이라 하고, 반대로 변환하는 것을 '언박싱(unboxing)' 이라고 한다.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(10); // 오토박싱. 10 -> new Integer(10)
int value = list.get(0); // 언박싱. new Integer(10) -> 10
위 코드에서 알 수 있듯이 ArrayList에 숫자를 저장하거나 꺼낼 때, 기본형 값을 래퍼클래스의 객체로 변환하지 않아도 된다.
1) 예제
int i = 10;
// 기본형을 참조형으로 형변환 (형변환 생략가능)
Integer intg = (Integer) i;
Object obj = (Object) i;
Long lng = 100L; // Long lng = new Long(100L)
int i2 = intg + 10; // 참조형과 기본형간의 연산 가능
long l = intg + lng; // 참조형 간의 덧셈도 가능
Integer intg2 = new Integer(20);
int i3 = (int) intg2; // 참조형을 기본형으로 형변환도 가능
Integer intg3 = intg2 + i3;
결과값 :
i = 10
intg = 10
obj = 10
lng = 100
intg + 10 = 20
intg + lng = 110
intg2 = 20
i3 = 20
intg2 + i3 = 40
이 예제는 오토박싱(autoboxing)을 이용해 기본형과 참조형 간의 형변환과 연산을 수행하는 예를 보여준다.
지금까지 배워온것과 달리 기본형과 참조형 간의 형변환도 가능할 뿐만, 아니라 심지어 참조형 간의 연산도 가능하다.
그러나 사실 이 기능은 컴파일러가 제공하는 편리한 기능일 뿐 자바의 원칙이 바뀐 것은 아니다.
기본 생성자를 컴파일러가 자동으로 추가해 주듯 개발자가 간략하게 쓴 구문을 컴파일러가 원래 구문으로 변경해주는 것이다.
컴파일 전의 코드 | 컴파일 후의 코드 |
Integer intg = (Integer)i; Object obj = (Object)i; Long lng = 100L; |
Integer intg = Integer.valuOf(i) Object obj = (Object)Integer.valueOf(i) Long lng = new Long(100L) |