티스토리 뷰

반응형

우리는 Wrapper Class에 대해 알 필요가 있다. 스터디 취지에 맞게 기본적인 설명은 빼도록 하겠다. 자 그러면 Wrapper Class를 사용하면서 얻는 이점이 무엇일지 생각해보자.

 

무의미한 값을 명확하게 표시할 수 있다.

@Id @GeneratedValue
@Column(name = "user_id")
private Long id;

 

위 코드는 고유 식별 값을 저장 하기위한 Entity 객체의 멤버 변수이다. 우리는 보통 id를 Long으로 선언하는데 이유는 간단하다. null이 담길 수 있기 때문이다. 기본형 타입은 null을 담을 수 없어 default가 0이라는 의미 있는 값이 담기게 된다. 그렇기에 개발자의 실수로 값이 안들어 가더라도 0이라는 의미가 있는 리터럴 변수가 들어가기에 아무런 문제없이 동작하게 될 것이다.

이는 결국 돌이킬 수 없는 오류로 이어질 것이다. 그렇기 때문에 의미 없는 값인 null로써 확질한 예외 상황을 만들어 사전에 이러한 문제를 해결 할 수 있다.

 

Collection에서는 기본적으로 객체를 받아 동작한다.

Collection은 모든 인수를 객체 타입으로 받아온다. 그렇기 때문에 반드시 기본형이 아닌 Wrapper 클래스를 사용해야 한다. 그렇기 때문에 기본적으로 Collection 구조에 데이터를 넣기 위해선 박싱이 진행되고 출력할 땐 반대로 언박싱이 일어난다. 

/**
* 대표적인 Collection
*/
List<Integer> list = new ArrayList<>();

Map<String, Integer> = new HashMap<>();

위 코드 처럼 제네릭안에는 Wrapper 클래스가 위치해 있다. 

 

우리는 Wrapper 클래스가 왜 필요한지에 대해 알아보았다. 자 그럼 Wrapper 클래스에 대해 좀 더 깊이 들어가 보자

 

1. 박싱과 언박싱

  • 박싱

박싱은 기본형을 Wrapper 클래스로 바꾸는 것을 말한다.

Integer i = new Integer(3); // 박싱

하지만 자바는 오토 박싱을 지원하기 때문에 굳이 이런식의 선언 보다는

Integer i = 3; // 오토 박싱

오토박싱을 이용하여 더 편하게 바꿔주고 있다. 보통은 오토박싱을 이용하여 박싱해주는게 대부분이다.

 

  • 언박싱

언박싱의 정의는 간단하다 박싱을 해줘서 Wrapper 클래스로 바꿔줬다면 그걸 다시 기본형으로 바꿔주는게 언박싱이다.

Integer i = new Integer(3); // 박싱
int i2 = i.intValue(); // 언박싱

래퍼 클래스를 intValue() 메서드를 사용하여 기본형으로 바꿔줄 수 있다.

 

이 또한 오토 언박싱이 존재하기 때문에 보통 언박싱도 오토 언박싱으로 사용을 많이 하고 있다.

Integer i = 3; // 오토 박싱
int i2 = i; // 오토 언박싱

위와 같이 설정하는 것이 가장 보편적이라고 할 수 있다.

 

그렇지만 Wrapper 클래스는 기본적으로 객체기 때문에 Heap메모리에서 관리가 된다. 그리고 heap 메모리는 모두가 잘 알다 싶이 스레드가 공유를 하고 있기 때문에 Thread-safe하지 않다면 자칫 위험할 수가 있다.

 

하지만 다행이게도 자바는 이를 완벽히 해결해 냈다. 

 

불변 객체 Wrapper 클래스

다수의 쓰레드가 같은 자원에 접근하고 쓰기 작업을 시도한다고 하면 데이터를 동시에 여러 스레드가 자유자제로 바꾸게 될 것이다. 그리고 그렇게 된다면 자신이 의도한 값과는 전혀 다른 값을 받을 것이다. 그렇기 때문에 heap 메모리에 여러 스레드가 접근하여 마구잡이로 삭제 변경을 하게 해선 안된다. 

 

그래서 자바에 Wrapper 클래스들은 기본적으로 불변객체이다. 

class가 기본적으로 final 키워드가 붙어 불변성이 보장되는 것을 볼 수 있다. 그래서 우리는 Thread-safe하게 유지할 수 있다. 하지만 불변 객체이므로 값의 변경이 불가능하다는 단점이 있다. 오로지 읽기만 가능하게 만들어 놓아 사실 쓰레드가 자원을 공유하여 자유롭게 변경하지 못하게 막아놓은 것이다.

 

실제로 테스트를 해보았다.

public class Ex1 {

    public static void main(String[] args) {
        Integer x = 3;
        x ++;

        System.out.println(x);
    }
}

실제로 출력을 해보면 4가 나온다. 불변 객체인데 값을 변경 못하는게 아니야? 라고 말하시는 분들이 계실 것이다. 이는 바이트 코드를 살펴보면 알 수 있는데

intValue()를 통해 기본형으로 바꿔 연산을 수행하고 다시 Integer.valueOf()라는 정적 팩토리 메서드를 이용해 Integer형으로 바꿔주고 있다. 이 동작으로 우리는 Integer를 별 생각없이 연산할 수 있는 것이다. 하지만 이는 분명히 잘못된 사용이고 심각한 문제를 발생시킬 수 있다.

 

예를들어 다른 Thread가 증가 시키는 동안 다른 Thread가 들어와 같이 읽기를 수행한다면 해당 클라이언트는 증가된 값을 받게 될 것이다. 

 

이러한 문제를 해결하기위한 여러가지 방법 중 Atomic이라는 구조가 있는데, 추 후에 진행하게 될 것이니 그 때 알아보도록 하자

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함