불변 객체(Immutable Object) : 한 번 생성되면 내부 상태(필드 값)를 변경할 수 없는 객체

 즉, 객체가 생성된 이후에는 해당 객체의 상태를 변경하는 어떤 메서드나 동작도 존재하지 않음

 

대표적인 불변 객체의 예:

String 클래스

Integer, Long, Double 등 기본형 래퍼 클래스

 

불변 객체의 장점

1. 내부 상태 변경 불가
	객체가 생성된 이후에는 그 값이 변경되지 않음
	모든 필드는 final로 선언되어야 하며, 생성자에서만 초기화 가능
	
2. 가비지 컬렉션의 성능을 높일 수 있음 
	불변객체를 이용하면 GC의 스캔빈도와 범위가 줄게되어 GC의 성능에 도움이 됨
    
3. equals와 hashCode의 안정성 보장
	객체의 상태가 변하지 않기 때문에, 해시 기반 컬렉션(HashMap, HashSet 등)에서 안전하게 사용가능
    
4. 스레드 안전성(Thread-Safety) 
	불변 객체는 항상 동일한 값을 보장하므로 동기화를 신경쓸 필요가 없음
    병렬 프로그래밍에 유용함
* 멀티 스레드 환경에서는 공유 자원에 대해 서로 변경하면 값이 덮어씌워지는 문제가 발생

 

불변 객체를 선호하고 중요하게 여기는 이유

1.	스레드 안전성
	불변 객체는 여러 스레드에서 동시에 사용되더라도 상태가 변경되지 않으므로 
    동기화 코드 없이 안전하게 사용할 수 있다
	ex. String 클래스는 스레드 간 안전하게 공유 가능
2.	안정성과 신뢰성
	객체의 상태가 변하지 않으므로 한 번 설정된 값은 변하지 않는다
	디버깅과 유지보수가 용이
3.	캡슐화 강화
	불변 객체는 내부 상태가 외부에 노출되지 않도록 설계되기 때문에 캡슐화 원칙을 강화
	불변성을 유지하기 위해 외부에서 내부 필드에 접근할 수 없도록 방지
4.	캐싱과 재사용 가능
	불변 객체는 상태가 변하지 않으므로 동일한 상태를 가진 객체를 캐싱하여 재사용 가능
	ex. Integer 클래스의 valueOf 메서드는 -128부터 127 사이의 값을 캐싱하여 성능을 최적화
5.	컬렉션에서 안정적 동작
	불변 객체는 HashMap, HashSet 등의 컬렉션에서 안정적으로 동작
	해시 기반 컬렉션에서는 객체의 상태가 변경되면 해시 충돌이 발생할 수 있는데, 불변 객체는 이런 문제를 방지

 

불변 객체의 단점

1.	초기화 시 성능 비용
	불변 객체를 새로 생성하려면 기존 객체를 복사하여 새로운 객체를 생성해야 하므로 메모리와 CPU 비용이 증가할 수 있음
	다만, 작은 크기의 객체나 캐싱 기법을 통해 이러한 비용을 줄일 수 있음
2.	메모리 사용량 증가
	상태가 변할 때마다 새로운 객체를 생성하므로, 가변 객체보다 더 많은 메모리를 소비할 수 있음
	* 주로 대량의 데이터를 처리할 때 문제

 

불변 객체 설계 방법

1. 모든 필드를 final로 선언:

private final String name;
private final int age;

2. 클래스를 final로 선언 (상속 방지):

public final class Person {
    // 필드 및 생성자
}

3. 생성자를 통해 필드를 초기화:

public Person(String name, int age) {
    this.name = name;
    this.age = age;
}

4. 필드에 대한 getter는 원시값이나 불변 객체만 반환:

public String getName() {
    return name;
}


5. 참조 타입 필드는 복사본을 반환:

private final List<String> hobbies;

public Person(String name, int age, List<String> hobbies) {
    this.name = name;
    this.age = age;
    this.hobbies = new ArrayList<>(hobbies); // 방어적 복사
}

public List<String> getHobbies() {
    return Collections.unmodifiableList(hobbies); // 불변 리스트 반환
}

불변 객체의 활용 예시
1. 불변 객체 클래스

public final class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + '}';
    }
}


2. 사용 예

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 25);

        System.out.println(person); // 출력: Person{name='Alice', age=25}

        // 상태 변경 불가
        // person.setName("Bob"); // 컴파일 에러 발생
    }
}

 

 

참고 : 

https://devoong2.tistory.com/entry/Java-%EB%B6%88%EB%B3%80-%EA%B0%9D%EC%B2%B4Immutable-Object-%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90

 

'Java' 카테고리의 다른 글

Try With Resource  (2) 2025.01.22
Record Class (불변 데이터 클래스)  (2) 2025.01.17
제네릭(Generic)  (0) 2025.01.17