기본형과 참조형

<aside> 💡

자바의 데이터 타입은 크게 기본형(Primitive)타입과 참조형(Reference)타입이 있다.

</aside>

기본형 예제

public class PrimitiveMain {
    public static void main(String[] args) {
        // 기본형은 절대로 같은 값을 공유X
        int a = 10;
        int b = a;

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

        b = 20;
        System.out.println("20 -> " + b);
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
===================================================
/*
결과
a = 10
b = 10
20 -> 20
a = 10
b = 20
*/

기본형 변수는 절대로 같은 값을 공유하지 않는다. 결과에는 같은 값을 가지고 있는 것처럼 보이지만 b에 a의 값을 대입해도 a의 값을 공유하는 것이 아닌, 서로 다른 10 이라는 값을 가지게 된다.

참조형 예제

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("부산"); // b의 값을 부산으로 변경
        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='부산'}
*/

참조형은 참조값을 복사해서 대입하기 때문에 여러 변수에서 같은 객체를 공유 가능하다. 인스턴스를 생성하면 참조값을 복사해서 전달하기 때문에 b에 a의 참조값을 복사해서 대입한다. a와 b는 같은 Adress인스턴스를 참조하기 때문에 b의 값을 부산으로 변경하면 a도 같은 인스턴스를 참조해서 부산으로 변경된다.

사이드이펙트

<aside> 💡

주된 작업 외에 추가적인 부수 효과를 일으키는 것 보통 프로그래밍에서 부정적인 의미로 사용되는데, 프로그램의 특정 부분에서 발생한 변경이 의도치 않게 다른 부분에 영향을 미치는 경우에 발생한다.

</aside>

불변객체 - 객체의 상태가 변하지 않는 객체

<aside> 💡

공유하면 안되는 객체를 여러 변수에서 공유하면 위와 같은 문제가 발생할 수 있는데, 공유를 막을 방법은 없다. 하지만, 객체 공유 자체가 문제는 아니다. 객체공유를 한다고해서 바로 사이드이펙트가 터지는건 아니다. 위 문제의 직접적인 원인은 객체의 값을 변경한 것이다.

</aside>

코드예제

public class ImmutableAddress {
    private final String value; // final설정으로 값변경 불가

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

    public String getValue() {
        return value;
    }
    
    /*
    값 변경 불가이므로 setter메서드 삭제
    (있어봐자 의미가 없음 어차피 값 변경 불가)
    */

    @Override
    public String toString() {
        return "Address{" + "value='" + value + '\\'' + '}';
    }
}

불변객체를 만드는 방법은 간단하다. 어떤 방식이든 객체를 변경할 수 없게 만들면 된다. 위의 예제처럼 값을 final로 설정하면 다른 곳에서 value의 값을 변경 할 수 없기 때문에 ***위의 문제처럼 값을 변경함으로써 생기는 문제를 방지할 수 있다.

(애초에 setter를 작성하지않으면 value가 private이기 때문에 값을 변경 할 수 없긴 하다.)***