Java Mid 06 - Wrapper Class

기본형의 한계

래퍼 클래스를 들어가기 전 우선 자바에 대해 다시 짚고 넘어가자면 자바는 객체지향 언어이다. 그런데 자바 안에 객체가 아닌 것이 있다. (int, boolen, double)과 같은 Primitive Type들을 말한다. 기본형은 객체가 아니기 때문에 다음과 같은 한계가 있다.

  • 객체가 아니다. 기본형은 객체가 아니기 때문에 객체지향의 장점을 살릴 수 없다. 쉽게 생각해보자면 객체는 유용한 메서드를 제공할 수 있는데, 기본형은 객체가 아니기 때문에 메서드를 제공할 수 없다.
    • 객체 참조가 필요한 컬렉션 프레임워크를 사용하기 힘들다. 제네릭도 사용할 수 없다.
  • null 값을 가질 수 없다. 기본형 데이터 타입은 null을 가질 수 없다. 데이터가 없음 이라는 상태를 나타내야 할 때가 있는데 기본형은 null값을 가질 수 없다.

Wrapper클래스를 간단하게 설명하자면

기본 자료타입(primitive type)을 객체로 다루기 위해서 사용하는 클래스들을 래퍼 클래스(wrapper class)라고 한다. Wrapper가 감싸다 라는 뜻이 있는데 기본형을 감싸면 객체가 된다.

public class MyIntegerMethodMain0 {
    public static void main(String[] args) {
        int value = 10;
        int i1 = comPareTo( value, 5 );
        System.out.println( "i1 = " + i1 );
        int i2 = comPareTo( value, 10 );
        System.out.println( "i2 = " + i2 );
        int i3 = comPareTo( value, 20 );
        System.out.println( "i3 = " + i3 );

    }

    public static int comPareTo(int value, int target) {
        if (value < target) {
            return -1;
        } else if (value > target) { //그게아니라
            return 1;
        } else{ //이것도 아니고 저것도 아니면 ?
            return 0;
        }
    }
}

value와 비교 대상 값을 compareTo()라는 외부 메서드를 사용해서 비교한다. 자기 자신인 value와 다른값을 연산하는 것이기 때문에 항상 자기 자신의 값인 value가 사용된다. value가 객체라면 value객체 스스로 자기 자신의 값과 다른 값을 비교하는 메서드를 만드는 것이 더 중요하다.

한계 극복 직접 만든 래퍼 클래스

int를 클래스로 만들자. int를 클래스로 감싸서 만드는 것, 특정 기본형을 감싸서 만드는 클래스를 래퍼클래스라고 한다.

public class MyInteger {

    private final int value;

    public MyInteger(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public int comPareTo(int target) {
        if (value < target) {
            return -1;
        } else if (value > target) {
            return 1;
        } else{ 
            return 0;
        }
    }

    @Override
    public String toString() {
        return String.valueOf( value ); //숫자를 문자로 반환
    }
}
public class MyIntegerMethodMain1 {
    public static void main(String[] args) {
        MyInteger myInteger = new MyInteger( 10 );
        int i1 = myInteger.comPareTo( 5 );
        int i2 = myInteger.comPareTo( 10 );
        int i3 = myInteger.comPareTo( 20 );
        System.out.println( "i1 = " + i1 );
        System.out.println( "i2 = " + i2 );
        System.out.println( "i3 = " + i3 );

    }
}

래퍼 클래스- 기본형의 한계

기본형과 Null

  • 기본형은 항상 값을 가져야 한다. 하지만 때로는 데이터가 ‘없음’이라는 상태가 필요할 수 있다.
public class MyIntegerNullMain0 {
    public static void main(String[] args) {
        int[] intArr = {-1, 0, 1, 2, 3};
        System.out.println( findValue( intArr, -1 ) ); //-1 찾으면 -1 반환
        System.out.println( findValue( intArr, 0 ) );
        System.out.println( findValue( intArr, 1 ) );
        System.out.println( findValue( intArr, 100 ) );
    }

    private static int findValue(int[] intArr, int target) {
        for (int value : intArr) {
            if (value == target) {
                return value;
            }
        }
        return -1;
    }
}
  • findValue()는 배열에 찾는 값이 있으면 해당 값을 반환하고, 찾는 값이 없으면 -1을 반환한다.
  • findValue()는 결과로 int를 반환한다. int와 같은 기본형은 항상 값이 있어야 한다. 반환 값을 찾지 못하면 숫자 중에 하나를 반환해야 하는데 보통 -1 또는 0을 사용한다.
  • 100을 입력해도 -1을 반환한다.
    • 입력값이 -1일 때를 생각해보면, 배열에 -1 값이 있어서 -1을 반환한 것인지, 아니면 -1값이 없어서 -1을 반환한 것인지 명확하지 않다.
public class MyIntegerNullMain1 {
    public static void main(String[] args) {
        MyInteger[] intArr = {new MyInteger( -1 ), new MyInteger( 0 ), new MyInteger( 1 )};
        System.out.println( findValue( intArr, -1 ) ); //-1 찾으면 -1 반환
        System.out.println( findValue( intArr, 0 ) );
        System.out.println( findValue( intArr, 1 ) );
        System.out.println( findValue( intArr, 100 ) );
    }

    private static MyInteger findValue(MyInteger[] intArr, int target) {
        for (MyInteger myInteger : intArr) {
            if (myInteger.getValue() == target) {
                return myInteger;
            }
        }
        return null; //target이랑 비교후 값이 없다면 Null반환
    }
}
  • 앞서 만든 MyInteger 래퍼 클래스를 사용했다.
  • 실행 결과를 보면 -1을 입력했을 때는 -1을 반환한다.
  • 100을 입력했을 때는 값이 없다는 null을 반환한다
public class WrapperClassMain {
    public static void main(String[] args) {
        Integer newInteger= new Integer( 10 ); //미래에 삭제예정, 대신에 valueOf()를 사용
        Integer integerObj = Integer.valueOf( 10 ); //-128 ~ 127 자주 사용하는 숫자 값 재사용, 불변
        Long longObj = Long.valueOf( 10 );
        System.out.println( "newInteger = " + newInteger );
        System.out.println( "integerObj = " + integerObj );

    }
}

래퍼 클래스 생성 - 박싱(Boxing)

  • 기본형 10을 넣어서 Intger라는 래퍼클래스를 만드는 것 → 박싱
  • Integer.valueOf()에는 성능 최적화 기능이 있다.
  • -128 ~ 127범위의 Integer 클래스를 미리 생성해준다. 해당 범위의 값을 조회하면 미리 생성된 Integer 객체를 반환한다.
    • 마치 문자열 풀과 비슷하게 자주 사용하는 숫자를 미리 생성해두고 재사용한다.
    • 최적화 방식은 미래에 더 나은 방식으로 변경이 될 수 있다.

intValue() - 언박싱(Unboxing)

  • 래퍼 클래스에 들어있는 기본형 값을 다시 꺼내는 메서드이다.
  • 박스에 들어있는 물건을 꺼내는 것 같다고 해서 언박싱이라 한다.

결론 : 기본형 → 클래스 ( 박싱 ), 클래스 → 기본형 ( 언박싱 )

래퍼 클래스와 성능

래퍼 클래스는 객체이기 때문에 기본형보다 다양한 기능을 제공한다.

그렇다면 더 좋은 래퍼 클래스만 제공하면 되지 기본형을 제공하는 이유는 뭘까?

이유는 성능차이가 있기는 하다. 시기 적절하게 잘 사용해야 한다.

package lang.wrapper;

public class WrapperVsPrimitive {

    public static void main(String[] args) {
        int iterations = 1_000_000_000; //구분자
        long startTime, endTime;

        // 기본형 long 사용
        long sumPrimitive = 0;
        startTime = System.currentTimeMillis();
        for (int i = 0; i < iterations; i++) {
            sumPrimitive += i;
        }

        endTime = System.currentTimeMillis();
        System.out.println( "sumPrimitive = " + sumPrimitive );
        System.out.println( "기본 자료형 long 실행시간: " + (endTime - startTime) + "ms" );

        // 래퍼 클래스 Long 사용

        Long sumWrapper = 0L;
        startTime = System.currentTimeMillis();
        for (int i = 0; i < iterations; i++) {
            sumWrapper += i; // 오토 박싱 발생
        }

        endTime = System.currentTimeMillis();
        System.out.println( "sumWrapper = " + sumWrapper );
        System.out.println( "래퍼 클래스 Long 실행시간: " + (endTime - startTime) + "ms" );

    }
}

Reference

인프런 김영한님의 실전 자바 강좌 + 나의 뇌



© 2022. by taewoo

Powered by taewoo