객체의 상태, 즉 객체 내부의 값이나 필드, 멤버 변수가 변하지 않는 객체를 불변 객체라고 한다.
그렇다면 불볍 객체를 왜 사용하는 것일까? 기본형과 참조형의 공유에 대해서 먼저 알아본다.
1. 기본형과 참조형의 공유
자바의 데이터 타입을 보면 크게 다음의 타입으로 나눌 수 있다.
- 기본형 : 하나의 값을 여러 변수에서 절대로 공유하지 않음
- 참조형 : 하나의 객체를 참조값을 통해 여러 변수에서 공유함
1.1. 기본형 예제
기본형 : 하나의 값을 여러 변수에서 절대로 공유하지 않는다.
→ b = a 라고 하면 자바는 항상 값을 복사해서 대입한다.
1.2. 참조형 예제
- b = a 라고 할 경우 a라는 인스턴스의 메모리 참조값인 x001을 b에 대입하는 것이다.
참조형 예제에서 볼 수 있듯이, 여러 변수가 하나의 객체를 공유하는 것을 막을 방법은 없다.
→ 변수 a, b가 서로 각각 새로운 인스턴스를 생성하면 서로 다른 참조값을 바라보기 때문에 해결되긴 하지만 이를 강제할 수 있는 방법은 현재로써는 없다.
그럼 공유 참조로 발생하는 문제를 어떻게 해결할 수 있는 것인가?
2. 불변 객체 - 도입
지금까지 발생한 문제를 잘 생각해보면 공유하면 안되는 객체를 여러 변수에서 공유했기 때문에 발생한 문제이다.
하지만 살펴보았듯이 객체의 공유를 막을 수 있는 방법은 없다.
즉, 문제의 직접적인 원인은 공유된 객체의 값을 변경한 것에 있다.
불변 객체 : 객체의 상태(객체 내부의 값, 필드, 멤버 변수)가 변하지 않는 객체이다.
앞서 만들었던 Address 클래스를 Immutable Class로 만들어보자.
- ImmutableAddress 내 value는 final 타입이기 때문에 값을 변경할 수 없다.
- 따라서 setValue() 메서드 자체를 사용할 수 없다.
- 따라서 b라는 객체 내 value 값을 변경하기 위해서는 새로 인스턴스를 생성해서 b 값에 대입해줘야 한다.
- 결과적으로 a, b는 서로 다른 인스턴스를 참조하고 a가 참조하던 ImmutableAddress는 그대로 유지된다.
2.1. 정리
불변이라는 단순한 제약을 통해 사이드 이펙트를 막을 수 있다.
→ 객체의 공유 참조는 막을 수 없다. 그래서 객체의 값을 변경하면 다른 곳에서 참조하는 변수의 값도 함께 변경되는 사이드 이펙트가 발생한다. 사이드 이펙트가 발생하면 안되는 상황일 경우 불변 객체를 만들어서 사용하면 된다.
2.2. 참고 - 가변 객체 vs 불변 객체
Address는 가변 클래스이다. 이 클래스로 객체를 생성하면 가변 객체가 된다.
ImmutableAddress는 불변 클래스이다. 이 클래스로 객체를 생성하면 불변 객체가 된다.
4. 불변 객체 - 심화 예제
조금 더 심화적인 예제를 확인해본다.
- MemberV2는 주소를 변경할 수 없는 ImmutableAddress 클래스를 멤버 변수로 사용한다.
- MemberB의 주소를 변경할 때 setValue의 매개변수로 (new ImmutableAddress(”부산”)) 이라는 새로운 인스턴스를 생성한 뒤 새로운 참조값을 전달한다. → MemberA는 기존 주소를 그대로 유지할 수 있게 된다.
5. 불변 객체의 값 변경
불변 객체를 사용하지만 그대로 값을 변경해야 하는 메서드가 필요하다면?
5.1. 가변 객체에서는 어떻게 할까?
- MutableObj을 새로 생성하고 10이란 값을 넣어준다.
- obj(참조값)에 있는 add 메서드에 20을 매개변수로 전달한다.
- 인스턴스 변수의 값인 value에 addValue(20)이 전달되어 30으로 변경된다.
- obj.getValue()를 호출하면 30이 출력된다.
5.2. 불변 객체에서는 어떻게 하는가?
불변 객체를 설계할 때 기존 값을 변경해야 하는 메서드가 필요할 수 있다.
→ 이럴 때 기존 객체의 값은 그대로 두고 변경된 결과를 새로운 객체에 담아서 return 값으로 반환하면 된다.
→ 결과를 보면 기존 값은 그대로 유지되는 것을 확인할 수 있다.
- add(20) 메서드를 호출한다.
- 기존 객체의 인스턴스 변수(value) 값인 10과 인수로 전달된 20을 result 변수로 담아둔다.
- 이 때 기존 객체의 값을 변경할 수 없기에 계산 결과를 기반으로 새로운 객체를 만들어서 반환한다.
- 새로운 객체는 x002 참조를 가진다. 새로운 객체의 참조값을 obj2에 대입해준다.
'Programming > Java' 카테고리의 다른 글
[Java] 김영한의 자바 중급 1편 #4 - 래퍼 클래스 (0) | 2024.09.30 |
---|---|
[Java] 김영한의 자바 중급 1편 #3 - String 클래스 (0) | 2024.09.10 |
[Java] 김영한의 자바 중급 1편 #1 - Object 클래스 (0) | 2024.09.03 |
[Java] Local 개발 환경 구축 : Spring MVC (0) | 2021.06.27 |
[Java] Java 기초 지식 정리 (0) | 2021.06.27 |