자바의 Immutable Object(불변 객체) 에 대해서 다뤄보려고 한다.
불변 객체가 무엇이고 왜 필요한 것일까? 그리고 어떻게 사용되고 있는 것일까?
1. 불변 객체란 무엇일까?
"객체 지향 프로그래밍에 있어서 불변객체는 생성 후 그 상태를 바꿀 수 없는 객체를 말한다. 반대 개념으로는 가변 객체로 생성 후에도 상태를 변경할 수 있다"라고 정의되어 있다. 명료하지만 예시를 바로 떠올릴 수 없어서 다소 추상적이기도 하다.
먼저 예시를 들면 자바에서 제공하는 기본 Wrapper Class ( String, Integer , Boolean ... ) 가 불변 객체에 해당한다.
2.불변객체에 대한 메커니즘 이해
우리가 생성하는 객체와 자바의 String,Integer 와 같은 기본객체들은 어떤 차이가 있을까?
개발자들은 글을 보는 것보다 코드를 통한 이해가 더 빠르기 때문에 바로 예시를 들어 이야기 해보자.
우리가 정의한 A라는 클래스의 인스턴스를 생성하고, 해당 인스턴스를 myObject1,myObject2라는 변수가 참조할 때, 같은 곳을 참조하게 되고, A 오브젝트의 name 필드값이 변경되면 같은곳을 참조하고 있기 때문에 둘다 Bye라는 값을 반환한다.
우리가 정의한 클래스 말고 자바에 정의된 기본객체들은 아래와 같은 간단한 코드가 있을 때 어떻게 동작할까 ?
우리가 정의한 객체와 같은 메커니즘으로 동작한다면 Hello,hi 가 아닌 hi,hi 가 나와야 한다.
하지만 불변객체로 설계된 기본객체들은 참조값의 값을 변경하는 것이 아니라 새로운 공간에 새로운 값을 할당한다.
즉, example1과 exampl2 가 같은 주소값(1번지라고 예시를 들겠음) 을 바라보고 있고 example2를 통해 새로운 문자열 "hi" 로 값을 변경한다해도 example1은 기존과 동일하게 1번지를 바라보게 되고 example2는 hi가 위치하고 있는 새로운 번지수를 바라보게 된다.
3. 왜 불변객체를 사용하는가?
- 스레드 안전성: 여러 스레드가 동시에 같은 불변 객체를 참조하더라도, 어느 한 스레드가 객체의 상태를 변경할 수 없기 때문에 동기화 문제가 발생하지 않는다. 이는 복잡한 동기화 로직 없이도 데이터 일관성을 유지할 수 있게 해준다.
이해를 돕기 위한 시나리오를 추가하자면
- A가 "Hello"라는 데이터를 가진 String 객체를 읽고 있을 때, 이 데이터는 메모리에 저장된 후 변경될 수 없다. 즉, 객체 내부의 데이터는 생성 시점의 상태로 고정된다.
- B의 변경 시도: B가 같은 "Hello" 값을 변경하고 싶다면, String 객체는 변경할 수 없기 때문에 새로운 String 객체를 생성해야 한다. 예를 들어, B가 "Hello"에 "Bye"를 추가하고 싶다면 new String("HelloBye")와 같은 새로운 객체를 만들 수 있다. 하지만 이는 원래 A가 참조하고 있는 "Hello" 객체와는 전혀 다른, 새로운 메모리 주소에 저장된 객체이다.
- 결과: 따라서 A가 읽고 있는 "Hello" String 객체는 그대로 유지되며, B의 작업은 원래 객체에 영향을 주지 않는다. A는 여전히 원본 "Hello" 데이터를 안전하게 읽을 수 있다.
- 데이터 일관성: 불변 객체를 사용하면 데이터의 신뢰성이 보장된다. 데이터가 예측 가능하고, 오류 가능성이 줄어들어 버그 발생 확률이 낮아진다.
- 메모리 효율성: 같은 값의 불변 객체는 메모리에서 한 번만 생성되어 여러 참조에서 공유될 수 있다. 이는 메모리 사용을 최적화하고 성능을 개선하는 데 도움이 된다.
4.불변객체를 만드는 방법
1. setter를 사용하지 않는다. (객체의 상태를 변경하는 메소드 미제공)
2. private으로 선언한다.
3. final을 선언한다.
ImmutableCar객체를 보면 필드값을 수정할 수 없게 설계 되었다. 따라서 한번 지정한 값에 대해 불변이다.
하지만 불변객체 내에 가변객체를 참조받고 있다면 이야기가 달라진다.
ImmutableCar 객체를 불변객체로 설계하기 위해 다음과 같이 코드를 작성했다. 하지만 Sonata객체 자체가 가변객체이기 때문에 Sonata 객체의 version에 대한 수정은 열려있다. 그렇기 때문에 불변객체가 되려면 참조객체 역시 불변객체여야 한다는 것을 알 수 있다.
5. 자바의 불변 List
자바는 List를 불변으로 만드는 방법을 제공한다. Collections의 unmodifiableList와 List.of 를 통해 불변 리스트를 얻을 수 있다.
아래 예시와 같이 해당 리스트에 값을 추가하려고 하면 아래와 같은 친철한 Intellij의 설명과 , 오류를 만나게 된다.
하지만 위 Collections.unmodifiableList() 로 얻는 객체또한 완전한 불변이라고는 할 수 없는데, 만약 unmodifiableList의 element가 가변객체라면 위 Sonata의 예시처럼 가변객체 자체가 변경될 수 있다는점에 유의해야 한다.
'Java > Base' 카테고리의 다른 글
[Java] Wrapper 클래스와 Boxing , Unboxing (0) | 2023.09.14 |
---|