[Java] Wrapper 클래스

Bam·2024년 3월 10일
0

Java

목록 보기
53/98
post-thumbnail

Wrapper 클래스

기본형 변수를 다룰 때 부득이하게 기본형을 객체로써 다뤄야하는 경우가 발생합니다. 예를들면 매개변수로 객체만을 받거나, 값을 객체로만 저장해야하는 경우 등과 같은 상황들이 있습니다. 이런 경우에 기본형 변수들을 객체로 변경해서 작업을 수행해야합니다.

이때 기본형 변수들을 객체형으로 만들어주는 클래스가 바로 Wrapper 클래스입니다. 기본형 값을 객체로 포장하고 있다고해서 이런 이름이 붙었습니다.

Wrapper 클래스는 8가지 기본형을 객체로 다루게 해주는데, char, int를 제외하고는 기본형의 첫글자를 대문자로 만들어져있습니다.

기본형Wrapper 클래스
booleanBoolean
charCharacter
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble

이때 기본형을 Wrapper 클래스의 객체로 만드는 것을 박싱(boxing)이라고 하고 객체로부터 기본형값을 얻는 것을 언박싱(unboxing)이라고 부릅니다.

이때 한 번 박싱된 객체의 값은 변경할 수 없습니다. 즉, 래퍼 객체는 단순히 기본형을 객체로 만드는 일만 하는 것입니다.

그러면 기본형을 가지고 박싱과 언박싱을 수행해보겠습니다.

public class Main {
    public static void main(String[] args) {
        Integer integerObj = 10;	//박싱
        int integerValue = integerObj;	//언박싱

        System.out.println(integerObj.intValue());	//Integer 객체의 값을 int형으로 반환
        System.out.println(integerValue);
    }
}

참고로 연산시 래퍼 객체의 언방싱이 자동적으로 이루어집니다.

System.out.println(10 + integerObj);	//integerObj 언박싱 후 +연산 수행


문자열 변환

문자열 -> 기본형 변환 parseXxxxx()

Wrapper 클래스에는 String 타입의 값을 기본형으로 변경하는 메소드도 정의되어 있습니다. 이 메소드는 정적(static) 메소드로 정의되어 있습니다. 이 메소드를 사용해서 문자열을 8가지 기본형값으로 변경할 수 있습니다.

parseXxxxx()는 문자열을 기본형값으로 변환하고 반환합니다.

public class Main {
    public static void main(String[] args) {
        String str = "10";

        System.out.println(10 + str);	//문자열 연결 수행
        System.out.println(10 + Integer.parseInt(str));	//덧셈 연산 수행
    }
}

+ 연산자는 피연산자 중 한 쪽이 문자열이면 문자열을 연결하는 연산을 수행하고, 양쪽이 숫자라면 덧셈 연산을 수행합니다.

위에서 예시로든 intValue()와 헷갈리시면 안됩니다.
intValue()는 래퍼 클래스를 언박싱해서 int형 값을 반환하고, parseInt()는 문자열을 int형값으로 반환하는 메소드입니다.

또한 intValue()는 일반 메소드이므로 Integer 객체를 생성하고 사용해야하고, parseInt()는 정적 메소드이기 때문에 객체 선언없이 바로 사용할 수 있습니다.

문자열 -> Wrapper 클래스 변환 valueOf()

valueOf()는 문자열을 Wrapper 클래스로 변환해서 반환하는 메소드입니다.

Boolean bool = Boolean.valueOf("true");
Integer integer = Integer.valueOf("10");

오토 박싱 & 오토 언박싱

JDK 1.5 버전에서 오토 박싱과 오토 언박싱이 도입되면서 parseXxxxx()와 valueOf() 간의 차이가 없어졌습니다.

사실 위에서 작성한 코드가 손수 박싱을 하는 것이 아닌 오토 박싱과 오토 언박싱을 이용한 코드였습니다.

//박싱
int num = 10;
Integer integerNum = new Integer(num);

//오토 박싱
int num = 10;
Integer integerNum = num;
//언박싱
Integer integerNum = new Integer(10);
int num = integerNum.intValue();

//오토 언박싱
Integer integerNum = new Integer(10);
int num = integerNum;

따라서 어떤 메소드를 사용해도 오토 박싱과 오토 언박싱 덕분에 차이가 나지 않게되는데요. 한 가지 첨언을 하자면 valueOf()의 속도가 느리기 때문에 parseXxxxx()를 사용하는 것이 조금 더 좋다고 할 수 있습니다.

더 빠른 성능을 위해서라면 오토 박싱과 오토 언박싱에 맡기기보다는 동일한 타입으로 연산이 되게끔 하는 것이 제일 좋습니다.


Wrapper 객체 값 비교

Wrapper 객체==, != 연산은 값이 아닌 주소를 비교합니다. 결국 객체는 참조형이기 때문이죠.

public class Main {
    public static void main(String[] args) {
        Integer num1 = 1000;
        Integer num2 = 1000;

        System.out.println(num1 == num2);
    }
}

값은 동일하지만 서로 다른 객체이기 때문에 ==의 결과로 false를 반환합니다.

문제는 예외 사항인데요. 내부적으로 boolean, char, byte, short, int에서 아래 표에 명시된 범위 내의 값들은 같은 객체를 공유합니다.

타입범위
booleantrue, false
char\u0000 ~ \u007f
byte, short, int-128 ~ 127
public class Main {
    public static void main(String[] args) {
        Integer num1 = 10;
        Integer num2 = 10;

        System.out.println(num1 == num2);
        System.out.println(num1.equals(num2));
    }
}

int의 범위에 속하는 10이라는 값을 가진 두 객체를 ==equals()로 비교했을 때 결과는 둘 다 true로 값도 같고 객체도 동일하다라고 판정됩니다.

public class Main {
    public static void main(String[] args) {
        Integer num1 = 10;
        Integer num2 = 10;

        System.out.println(num1.hashCode());
        System.out.println(num2.hashCode());
    }
}

해시 코드가 같아버리면서 완전히 두 객체는 같다고 해버리죠.

이러한 동작 때문에 boolean, char, byte, short, int값을 사용할 때는 ==. !=보다는 equals()로 비교하는 것이 안정적인 결과를 얻을 수 있습니다.


Number 클래스

Number 클래스는 숫자 값을 가지는 Wrapper 클래스(Byte, Short, Integer, Long, Float, Double)의 조상 클래스입니다.

Number 클래스추상 클래스이기 때문에 숫자를 활용하는 Wrapper 클래스들의 메소드들을 추상 메소드 형태로 가지고 있습니다. 즉, Byte, Short, Integer, Long, Float, Double들에게 공통된 메소드(xxxxxValue()와 같은)들을 제공하기 위해 존재하는 클래스라고 할 수 있습니다.

이들 외에도 BigInteger, BigDecimal같은 클래스도 자식으로 가지고 있는데 BigInteger는 long의 범위보다 더 큰 정수를 처리하고, BigDecimal은 double의 범위보다 더 큰 부동소수점수를 처리하기 위해 존재하는 클래스입니다.

0개의 댓글