불변 클래스(Immutable Class)는 한 번 생성된 객체의 상태를 절대 변경할 수 없는 클래스를 말합니다. 즉, 객체가 생성된 후에 객체의 필드 값을 변경할 수 없는 특징을 가집니다. 자바에서 대표적인 불변 클래스는 String
, Integer
, Boolean
등이 있습니다.
불변 클래스의 장점은 특히 멀티스레드 환경에서 큰 효과를 발휘합니다. 불변 객체는 상태가 변하지 않으므로 여러 스레드가 동시에 객체에 접근해도 안전하게 사용할 수 있습니다. 또한, 값이 변경되지 않으므로 캐싱과 같은 최적화에도 유리합니다.
불변 클래스를 정의하려면 몇 가지 규칙을 따라야 합니다:
- 객체의 상태를 변경할 수 있는 메서드를 제공하지 않는다.
- 객체의 필드 값이 한 번 설정되면 그 값을 바꿀 수 있는 메서드를 제공하지 않습니다. 즉, setter 메서드를 만들지 않습니다.
- 모든 필드는
final
로 선언한다.- 필드가
final
로 선언되면 생성자를 통해서만 한 번 값이 설정될 수 있고, 그 이후에는 변경할 수 없습니다.
- 필드가
- 객체의 모든 필드는
private
으로 선언한다.- 객체 외부에서 직접 필드에 접근하지 못하도록 필드는
private
으로 선언합니다.
- 객체 외부에서 직접 필드에 접근하지 못하도록 필드는
- 변경 가능한 객체를 참조하는 필드는 객체의 복사본을 사용한다.
- 만약 클래스 내에 배열이나 다른 객체처럼 변경 가능한 객체를 필드로 가질 경우, 그 필드의 값을 반환하거나 전달할 때는 객체의 복사본을 제공하여 원래 객체가 변경되지 않도록 해야 합니다.
- 상속을 허용하지 않는다.
- 클래스 자체가 변경되면 불변성이 깨질 수 있기 때문에 불변 클래스를 설계할 때는 상속을 허용하지 않는 것이 좋습니다. 클래스에
final
을 붙여 상속을 막는 방식으로 이를 구현할 수 있습니다.
- 클래스 자체가 변경되면 불변성이 깨질 수 있기 때문에 불변 클래스를 설계할 때는 상속을 허용하지 않는 것이 좋습니다. 클래스에
다음은 자바에서 불변 클래스를 구현하는 방법에 대한 예시입니다.
java코드 복사public final class ImmutablePerson {
private final String name;
private final int age;
public ImmutablePerson(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
- 클래스에
final
키워드를 사용하여 상속을 방지합니다. - 모든 필드는
private
과final
로 선언되어 한 번 설정된 후 수정할 수 없습니다. - 클래스 내에 값을 변경하는 메서드(setter)를 제공하지 않습니다.
- 생성자를 통해서만 값을 설정할 수 있으며, 이후 객체의 상태는 변경되지 않습니다.
- 안전한 동시성 (Thread-Safety)
- 불변 객체는 상태가 변하지 않기 때문에 여러 스레드에서 동시에 접근해도 안전합니다. 스레드 간 동기화를 고려할 필요가 없으며, 멀티스레드 환경에서 성능상의 이점을 얻을 수 있습니다.
- 캐싱 및 공유 가능
- 불변 객체는 변하지 않으므로 여러 곳에서 안전하게 공유하거나 캐싱할 수 있습니다. 예를 들어
String
객체는 불변이기 때문에 자바는String
의 인스턴스를 재사용하는 내부 캐시를 사용합니다.
- 불변 객체는 변하지 않으므로 여러 곳에서 안전하게 공유하거나 캐싱할 수 있습니다. 예를 들어
- 안전한 복사
- 불변 객체는 원래 객체를 그대로 다른 곳에 전달해도 되므로 객체를 복사할 필요가 없습니다. 이로 인해 불필요한 메모리 낭비를 줄일 수 있습니다.
- 디버깅이 쉬움
- 불변 객체는 상태가 고정되어 있어 디버깅 시 객체 상태가 변경되지 않으므로 문제를 추적하기가 훨씬 쉽습니다.
- 값이 변경될 때마다 새로운 객체를 생성해야 함
- 불변 클래스는 객체의 상태를 변경할 수 없으므로 값이 변경될 때마다 새로운 객체를 생성해야 합니다. 이로 인해 객체가 자주 변경되는 경우에는 성능 상의 이슈가 발생할 수 있습니다.
- 복잡한 객체 구조
- 불변 클래스에서 필드가 다른 객체를 참조하는 경우, 복사본을 반환해야 하므로 코드가 복잡해질 수 있습니다.
이와 같이 불변 클래스는 자바에서 안전하고 신뢰성 높은 프로그램을 작성하는 데 도움을 주며, 특히 동시성 문제를 해결하는 데 큰 장점을 제공합니다.
모든 필드를 final
로 선언하여 객체가 생성된 후에 변경할 수 없게 합니다.
모든 필드를 생성자에서 초기화하여 객체가 생성될 때 모든 속성이 설정되도록 합니다.
객체의 상태를 변경할 수 있는 setter 메서드를 제공하지 않습니다. 대신, 필요할 경우 새로운 객체를 반환하는 메서드를 제공합니다.
필드가 참조형 객체인 경우, 해당 객체가 변경 불가능한 타입인지 확인하거나, 새로운 객체를 반환하는 방법을 사용합니다.
객체의 속성을 반환할 때는 직접 참조를 반환하지 않고, 복사본을 반환하여 외부에서 객체의 상태를 변경할 수 없도록 합니다.
public final class ImmutablePoint {
private final int x;
private final int y;
// 생성자
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
// Getter 메서드
public int getX() {
return x;
}
public int getY() {
return y;
}
// 새로운 객체를 반환하는 메서드
public ImmutablePoint move(int deltaX, int deltaY) {
return new ImmutablePoint(this.x + deltaX, this.y + deltaY);
}
}
final
키워드로 클래스와 필드를 선언하여 변경할 수 없도록 했습니다.- 생성자를 통해
x
와y
값을 초기화했습니다. move
메서드는 새로운ImmutablePoint
객체를 생성하여 반환합니다. 기존 객체는 변경되지 않습니다.
이런 방식으로 클래스를 설계하면, 불변성을 유지하면서도 필요한 경우 새로운 객체를 생성할 수 있습니다.