JAVA

Wrapper Class 와Primitive Type and First Class Collection

whyWhale 2021. 3. 21. 23:09

Wrapper Class ,Primitive Type 

 

 

8개의 기본타입을 객체로 포장해 주는 클래스를 래퍼 클래스라고 한다. 

 

래퍼 클래스는 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어 준다.(박싱)

 

 

기본 타입 -> 래퍼 클래스 (박싱)

래퍼 클래스 -> 기본 타입 (언박싱)

 

래퍼 클래스는 산술 연산을 위해 정의된 클래스가 아니다. 기본 타입은 값을 그대로 저장하지만 참조형인 객체는 레퍼런스 즉 주소를 저장한다. 그러므로 연산을 위해 정의된 클래스가 아니라는 것이다.  기본 타입은 null값을 가질 수 없다.

오토박싱과 오토 언방식

  •  래퍼 클래스의 객체의 인스턴스로 변환하는 과정을 Boxing 이라고 한다.
  •  래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정을 UnBoxing 이라고 한다.

※ 참조형과 기본형의 차이는 주소와 값의 차이로 인해 기본형 ==으로 비교가 가능하지만 참조형은 ==으로 비교할 수 가 없다(equals 사용).

 

JDK 1.5부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 이를 자동으로 처리해 준다.

이렇게 자동화된 박싱과 언박싱을 오토 박싱(AutoBoxing)과 오토 언박싱(AutoUnBoxing)이라고 부른다.

 

ex ) 타입Value()- 언박싱

 

오토 박싱/언박싱을 통해 기본 타입과 래퍼클래스 간의 연산이 가능해졌다.

 

 

메모리 할당량의 차이

int a=100;  // 4byte
Integer b=new Integet(100);  // 객체(클래스 포인터, 플래그, 락,값 각각 32bit) 총 128bit- > 16byte

 

대략 4배의 비용이 더 든다.

 

기본 배열또한 객체형인데 배열의 사이즈까지 포함해 대략 5배 더 비용이든다.


+_+

이전에 참조형과 기본형에 대해 참조형은 "equals" 사용하기로 했는데 이 부분에서 첫번째 마지막에서는 true 값을 반환한다. 

	Integer a=127;
        Integer b=127;

        Integer c=128;
        Integer d=128;

        Integer e=-128;
        Integer f=-128;

        System.out.println(a==b);// true 객체생성x 캐시에 있는 값 반환
        System.out.println(c==d);// false 캐시 값의 범위보다 크므로 객체 생성
        System.out.println(e==f); // true 객체생성x. 캐시에 있는 값 반환

Integer 래퍼 클래스에서 내부적으로 보면 -128 ~ 설정할 수 있는 최대값을 캐시에 저장해 새롭게 객체를 생성해서 반환해 주는 것이 아닌 캐시값의 범위면 바로 해당 값을 반환하므로 "=="을 사용하였을 때 true 가 나오는 것이다.

  @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
    // 캐시의 유효범위 값에 있는 수라면 return new Integer(i)가 아닌 캐시 값 반환.
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    
    
    private static class IntegerCache {
        static final int low = -128; // default 이며 변경되지 않아야 하는 값.
        static final int high;
        static final Integer[] cache;
        static Integer[] archivedCache;

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            .
            .
            .
            .
            .
            }

 

 

 


일급 컬렉션 (First Class Collection)

콜렉션을 포함한 클래스는 반드시 다른 멤버 변수가 없어야 한다.

각 콜렉션은 그 자체로 포장돼 있는 것이다.

필터가 이 클래스의 일부가 된다.

이 클래스를 두 그룹으로 같이 묶는다는가 그룹의 각 원소에 규칙을 적용하느느 등의 동작을 처리 할 수 있다.

컬렉션은 매우 유용한 원시 타입이다.

 

 

Collection만을 감싸고(그 외 다른 멤버 변수가 없는 상태).

static class Order{
      private final List<Order> orderList;

    Order(List<Order> orderList) {
        this.orderList = orderList;
    }
}

 

 Wrapping 함으로써의 이점.

  • 비즈니스에 종속적인 자료구조
  • Collection의 불변성 보장
  • 상태와 행위를 한 곳에 관리
  • 이름이 있는 컬렉션

1. 비즈니스에 종속적인 자료구조.

 

 static class GSConveniance {
        private List<IceCream> iceCreams;

        public GSConveniance(List<IceCream> iceCreams) {
            validateSize(iceCreams);
            this.iceCreams = iceCreams;
        }
        private void validateSize(List<IceCream> iceCreams) {
            if (iceCreams.size() >= 10) {
                new RuntimeException("아이스크림은 10개 이상의 종류를 팔지 않습니다.");
            }
        }
    }
    static class CUConveniance {
        private List<IceCream> iceCreams;
        public CUConveniance(List<IceCream> iceCreams) {
            validateSize(iceCreams);
            this.iceCreams = iceCreams;
        }
        private void validateSize(List<IceCream> iceCreams) {
            if (iceCreams.size() >= 10) {
                new RuntimeException("아이스크림은 10개 이상의 종류를 팔지 않습니다.");
            }
        }
    }

gs,cu 편의점들은 각각 같은 validate조건을 사용하는데 만약 이렇게 각각의 코드에 validate가 중복이 되고 클래스의 역할이 무거워 지게 된다. 이 부분을 일급 컬렉션을 활용하여 상태와 행위을 각각 관리할 수 있다.

 

static class IceCream{
       private List<IceCream> iceCreams;

        public IceCream(List<IceCream> iceCreams) {
            validateSize(iceCreams);
            this.iceCreams = iceCreams;
        }
        private void validateSize(List<IceCream> iceCreams) {
            if (iceCreams.size() >= 10) {
                new RuntimeException("아이스크림은 10개 이상의 종류를 팔지 않습니다.");
            }
        }
    }

일급 컬렉션의 사용.

 static class GSConveniance {
        private List<IceCream> iceCreams;

        public GSConveniance(List<IceCream> iceCreams) {
            this.iceCreams = iceCreams;
        }
    }
    static class CUConveniance {
        private List<IceCream> iceCreams;
        public CUConveniance(List<IceCream> iceCreams) {
            this.iceCreams = iceCreams;
        }
    }

 

2. 불변

불변은 '재 할당'을 금지하는 것이다. 그래서 final collection에 값을 집어넣는 것이 가능하다.

다른곳에서 new를 통해 한번 더 하는 '재 할당'이 안되는 것이다.

 

단순히 자바에서는 final로 불변의 문제를 해결 할 수 없기에 일급 컬렉션 또는 래퍼 클래스등의 방법으로 해결해야만 한다.

 

 

3. 상태와 행위를 한 곳에서 관리.

 

만약 네이버 페이의 결제 량만 보고 싶은 경우. 일급 컬렉션 내에서의 상태와 행위를 모두 한곳에서 관리 할 수 재사용이 가능하고 또는 외부에서 간단하게 코드를 작성할 수 있다.

public class PayGroups {
    private List<Pay> pays;

    public PayGroups(List<Pay> pays) {
        this.pays = pays;
    }

    public Long getNaverPaySum() {
        return pays.stream()
                .filter(pay -> PayType.isNaverPay(pay.getPayType()))
                .mapToLong(Pay::getAmount)
                .sum();
    }
}