[Java] 불변 객체

szlee·2024년 8월 13일
0

Java

목록 보기
25/34

< 김영한의 실전 자바 - 중급편 > 강의를 보고 이해한 내용을 바탕으로 합니다.





기본형과 참조형의 공유

자바의 데이터 타입은 크게 기본형과 참조형으로 나눌 수 있다.

  • 기본형 : 하나의 값을 여러 변수에서 공유하지 않는다.
  • 참조형 : 하나의 객체를 참조값을 통해 여러 변수에서 공유 가능하다.

기본형

public static void main(String[] args) {
 	//기본형은 절대로 같은 값을 공유하지 않는다.
 	int a = 10;
 	int b = a; // a -> b, 값 복사 후 대입
 	System.out.println("a = " + a); //a=10
 	System.out.println("b = " + b); //b=10
    
 	b = 20;
 	System.out.println("20 -> b"); 
 	System.out.println("a = " + a); //a=10
 	System.out.println("b = " + b); //b=20
 }

기본형 변수 a와 b는 절대로 하나의 값을 공유하지 않는다.
b=a라고 하면 자바는 항상 값을 복사해서 대입한다. 이 경우 a에 있는 값 10을 복사해서 b에 전달하고 결과적으로 a와 b는 둘다 똑같은 숫자의 값을 가지지만 이 둘은 완전히 다르다. 메모리 상에서도 별도로 존재한다.
=> 기본형 변수는 하나의 값을 절대로 공유하지 않는다.

참조형

public static void main(String[] args) {
 	//참조형 변수는 하나의 인스턴스를 공유할 수 있다.
 	Address a = new Address("서울");
 	Address b = a;
 	System.out.println("a = " + a); //a = Address{value='서울'}
 	System.out.println("b = " + b); //b = Address{value='서울'}
    
 	b.setValue("부산"); //b의 값을 부산으로 변경해야함
 	System.out.println("부산 -> b");
 	System.out.println("a = " + a); //a = Address{value='부산'}. 사이드 이펙트 발생
 	System.out.println("b = " + b); //b = Address{value='부산'}
 }

참조형 변수들은 같은 참조값을 통해 같은 인스턴스를 참조할 수 있다.
b=a라고 하면 a에 있는 참조값 x001을 복사해서 b에 전달한다.
자바에서 모든 값 대입은 변수가 가지고 있는 값을 복사해서 전달한다. 변수가 숫자값을 가지고 있으면 숫자값을 복사해서 전달하고, 참조값을 가지고 있으면 참조값을 복사해서 전달한다.
참조값을 복사해서 전달하므로 결과적으로 a,b는 같은 인스턴스(x001)를 참조한다.



공유 참조와 사이트 이펙트

해결방안

a와 b가 처음부터 서로 다른 인스턴스를 참조하도록 한다.

Address a = new Address("서울");
Address b = new Address("서울");

a와 b는 서로 다른 인스턴스를 참조하므로 b가 참조하는 인스턴스의 값을 변경해도 a에는 영향을 주지 않는다.

그런데 여기서 문제는 하나의 객체를 여러 변수가 공유하지 않도록 강제로 막을 방법이 없다.

Address a = new Address("서울");
Address b = a; //참조값 대입을 막을 수 있는 방법이 없다.

실수로 b=a 라고 해도 아무런 오류가 발생하지 않는다. 문법상 아무런 문제가 없기 때문이다. => 객체의 공유를 막을 수 있는 방법이 없다.



불변 객체

객체를 공유하는 것 자체는 문제가 아니고 객체를 공유한다고 바로 사이드 이펙트가 발생하지는 않는다. 문제의 직접적인 원인은 공유된 객체의 값을 변경한 것이다.
객체의 값을 변경하지 못하게 설계했다면 이러한 사이드 이펙트는 발생하지 않았을 것이다. => 불변 객체 등장.
불변 객체는 객체의 상태(객체 내부의 값, 필드, 멤버 변수)가 변하지 않는 객체를 말한다.

  • 멤버 변수를 final로 설정한다.
  • 값을 변경하는 메서드를 제거한다.

불변 객체를 사용하지만 값을 변경해야 하는 메서드가 필요하다면?
=> 기존 값은 변경하지 않고 대신 계산 결과를 바탕으로 새로운 객체를 만들어서 반환한다.

public class ImmutableObj {
 	private final int value;
    
 	public ImmutableObj(int value) {
 		this.value = value;
 	}
    
 	public ImmutableObj add(int addValue) {
 		int result = value + addValue;
 		return new ImmutableObj(result);
 	}
    
 	public int getValue() {
 		return value;
 	}
}

불변 객체에서 변경과 관련된 메서드들은 보통 객체를 새로 만들어서 반환하기 때문에 꼭! 반환 값을 받아야 한다.

profile
🌱

0개의 댓글