ToBe끝판왕

[ JAVA ] 불변 객체 ( 기본형과 참조형 ) 본문

■ 프로그래밍 SKILLS/JAVA

[ JAVA ] 불변 객체 ( 기본형과 참조형 )

업그레이드중 2024. 8. 12. 18:54
반응형



 


 


■ java.lang 패키지 에 관하여 알아보자 !

•  자바 언어를 이루는 가장 기본이 되는 클래스들을 보관하는 패키지

•  java.lang 패키지의 대표적인 클래스
-  Object : 모든 자바 객체의 부모 클래스
-  String : 문자열
-  Integer, Long, Double : 래퍼타입 , 기본형 데이터 타입을 객체로 만든 것

 

 

기본형( Primitive Type) 와 참조형( Reference Type )

 

•  기본형

-  하나의 값을 여러 변수에서 절대로 공유하지 않음

 

•  참조형

-  하나의 객체를 통해 여러 변수에서 공유 가능

 

 

•  기본형( Primitive Type ) 예시

-  b = a 에서 자바는 항상 값을 복사해서 대입한다.

-  a 와 b 둘다 10이란 같은 숫자의 값을 가지지만, a가 가지는 10과 b가 가지는 10은 완전히 다른 10이다.

-  메모리상에도 a에 속하는 10과 b에 속하는 10이 각각 별도로 존재한다.

package lang.immutable.address;

public class PrimitiveMain {

    public static void main(String[] args) {

        // 기본형은 절대로 같은값을 공유하지 않는다.
        int a = 10;
        int b = a;      // a -> b, 값 복사 후 대입

        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println();

        b = 20;
        System.out.println("20 -> b");

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
// 실행 결과

a = 10
b = 10

20 -> b
a = 10
b = 20

 

 

 

•  참조형( Reference Type ) 의 예시

-  Address b = a 코드에서 변수 a, b 둘다 서울이라는 주소를 가지게 된다.

-  이후, b의 주소를 부산으로 변경하는데 a의 주소도 함께 부산으로 변경이 된다. ( 문제점 )

-  Address b = a 코드에서 a의 참조값을 복사하여 b에 전달하는데, a와 b가 같은 참조값을 통하여 같은 인스턴스를 참조하게 되었다.

   ( a와 b 는 같은 참조값으로 같은 인스턴스를 참조하기 때문에 같이 부산으로 변경이 되는 원인 --> 사이드 이펙트 발생 )

-  

package lang.immutable.address;

public class Address {

    private String value;

    public Address(String value) {
        
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Address{" +
                "value='" + value + '\'' +
                '}';
    }
}
package lang.immutable.address;

public class RefMain1_1 {

    public static void main(String[] args) {

        // 참조형 변수는 하나의 인스턴스를 공유할 수 있다.
        Address a = new Address("서울");
        Address b = a;
        System.out.println("a = " + a);
        System.out.println("b = " + b);

        b.setValue("부산");
        System.out.println("부산 -> b");
        System.out.println("a = " + a);
        System.out.println("b = " + b);

    }
}
// 실행 결과

a = Address{value='서울'}
b = Address{value='서울'}

부산 -> b
a = Address{value='부산'}
b = Address{value='부산'}

 

 


 

 

불변객체( Immutable Object )

 

•  위와 같이, 여러 변수가 하나의 객체를 공유하는 것을 막을 방법이 없다.

•  참조값을 다른 변수에 대입하여 객체간의 공유가 일어나지만 자바 문법상 정상인 코드이다.

•  사이드 이펙트의 핵심은 공유 참조하는 인스턴스의 값을 변경하기 때문에 발생한다.

•  이를 해결 하기 위해 객체의 상태( 객체 내부의 값, 필드, 멤버변수 )가 변하지 않는 불변객체를 도입해야 한다.

 

 

•  불변객체(클래스) 예시

-  인스턴스 생성시 final 로 선언

-  생성자를 통해서만 값 설정 가능, 이후에는 값 변경 불가능

package lang.immutable.address;

public class ImmutableAddress {

	// 내부값이 변경되면 안되므로 final로 선언
    private final String value;

    public ImmutableAddress(String value) {
        
        this.value = value;
    }

    public String getValue() {
        
        return value;
    }
    
    // 내부값 변경이 가능한 setter 는 존재 X

    @Override
    public String toString() {
        return "Address{" +
                "value='" + value + '\'' +
                '}';
    }
}
package lang.immutable.address;

public class RefMain2 {

    public static void main(String[] args) {

        ImmutableAddress a = new ImmutableAddress("서울");
        ImmutableAddress b = a;     // 참조값 대입을 막을 수 있는 방법 X ( 자바 문법상 문제 X )
        System.out.println("a = " + a);
        System.out.println("b = " + b);

        // b.setValue("부산") 이 안됨 -> 불변객체 유추 , b의 값을 부산으로 변경해야함
        b = new ImmutableAddress("부산");
        System.out.println("부산 -> b");
        System.out.println("a = " + a);
        System.out.println("b = " + b);

    }
}
// 실행 결과

a = Address{value='서울'}
b = Address{value='서울'}

부산 -> b
a = Address{value='서울'}
b = Address{value='부산'}

 

 

 

•  불변객체를 사용하지만 값을 변경하는 메서드가 필요한 경우

-  불변객체는 기존값은 변경하지 않은채, 계산 결과를 바탕으로 새로운 객체를 만들어서 반환

-  불변도 유지하며 새로운 결과 또한 만들 수 있다.

 

package lang.immutable.change;

public class ImmutableObj {

    // 불변 객체 ( final 사용 ) , 절대 바뀌면 안된다.
    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;
    }

}
package lang.immutable.change;

public class ImmutableMain1 {

    public static void main(String[] args) {
        ImmutableObj obj1 = new ImmutableObj(10);
        ImmutableObj obj2 = obj1.add(20);

        // 계산 이후에도 기존값과 신규값 모두 확인 가능
        System.out.println("obj1 = " + obj1.getValue());
        System.out.println("obj2 = " + obj2.getValue());
    }
}
// 기존값이 변경해야 하는 메서드가 필요한 경우, 변경된 결과를 새로운 객체에 담아 반환
// 실행 결과

obj1 = 10
obj2 = 30

 

 

※  참고사항

•  불변 객체에서 값을 변경하는 메서드의 경우, "with"으로 이름을 시작하게 하는 경우가 많다.

 

 

 

※ 해당 내용은 인프런 김영한 강사님의  "실전 자바 중급1" 인강의 참고자료와 예시들을 참고하였습니다

반응형
Comments