Language/Java

[Java] Wrapper Class의 생성과 Cache

Deveun 2021. 9. 13. 04:53

Java의 데이터 타입은 크게 Primitive Type (기본형), Reference Type (참조형) 두가지가 있다.

Java의 기본형 변수는 참조형으로 바꿀 수 있는데 이를 Wrapper Class라고 한다.

 

 

Wrapper Class는 왜 쓰는걸까?

사실 코딩을 하면서 개발자가 직접 기본형 -> 참조형으로 변수 타입을 변경(Boxing)하는 일은 많지 않은 것 같다. JDK 1.5버전 이후부터 자동으로 변수타입을 바꾸어주기 때문인데, 내부적으로는 Wrapper Class는 몇가지 특징을 가진다.

 

1) 다형성

자주 쓰는 java.util.*의 Collections 함수들은 대부분 Object 타입으로 매개변수를 받고, 반환한다. 마찬가지로 Generic Type도 마찬가지다.

기본형의 변수를 Wrapper Class로 변환함으로써 사용할 수 있다.

 

2) 관련 메소드

Wrapper Class 내에는 기본 타입 변수 값(value) 뿐만 아니라 여러가지 메소드들이 정의되어 있다.

이 메소드들을 사용하여, 다른 타입으로 변경하거나 값을 비교하거나 등의 기능을 수행할 수 있다.

 

3) 캐시 기능

Wrapper class는 자주 쓰이는 값의 인스턴스를 생성하지 않도록 내부에서 캐시를 사용한다.

 

4) null 가능

 


valueOf 함수와 Cache

앞에서 살펴본 Wrapper Class의 특징중에서 캐시를 사용한다는 것을 알게되었는데, 이는 어떻게 사용되어지고 있을까?

 

먼저 Integer, Float, Boolean, Character와 같은 Wapper Class들의 생성자는 다음과 같이  Deprecated 되어 있다. 대신에 valueOf 메소드를 사용하라고 권유하고 있는데 (The static factory valueOf(int) is generally a better choice), 해당 메소드에서 cache를 사용하고 있었다.

 

[Integer.java]

    @IntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

위 Integer 클래스의 valueOf 메소드 정의부분을 보면 정수형 변수의 범위가 -128 <= i < 127일 때는 IntegerCache의 캐시값을 반환하고, 아닐 시에만 생성자를 통해 새로운 인스턴스를 생성하는 것을 확인할 수 있다.

IntegerCache 클래스는 내부의 static 블록에서 미리 new Integer(i) 로 범위 만큼의 인스턴스를 만들어둔다.

 

다른 정수형(Byte, Short, Long), Character Wrapper class도 동일한 방법으로 캐시를 사용하며, Boolean는 (b ? TRUE : FALSE) 로 구현되어 새로 인스턴스를 생성하지 않는다. 소수점 값을 가지는 실수형 타입의 Wrapper class (Float, Double)의 경우에만 캐시를 사용하지 않는다.

 

간단한 예제를 통해 확인해보자.

public static void main(String[] args) {

        Integer in1 = 100;
        Integer in2 = 100;
        Integer in3 = 300;
        Integer in4 = 300;

        if (in1 == in2) {
            System.out.println("in1 == in2");
        } else {
            System.out.println("in1 != in2");
        }
        if (in3 == in4) {
            System.out.println("in3 == in4");
        } else {
            System.out.println("in3 != in4");
        }
}


/* 실행결과 ****

in1 == in2
in3 != in4

****************/

 

실행결과를 보면  in1과 in2은 127보다 작은 정수이기 때문에 IntegerCache값을 가져와 동일한 인스턴스이고, in3과 in4는 더 큰 정수이기 때문에 새로운 인스턴스를 생성하여 주소값이 다른 것을 확인할 수 있다.

 

 

 

[참고]

https://meetup.toast.com/posts/185

https://jwdeveloper.tistory.com/140

https://100100e.tistory.com/353