본문 바로가기
public void static main/Java

[JAVA] 불변객체, 가변객 뭔지는 알겠는데 자세히 좀 더 알아보자

by 햄리뮤 2024. 12. 25.
반응형

음 String은 불변이고 StringBuffer 랑 StringBuilder는 가변이래 알겠어 알겠는데 그래서 구조랑 뭐 데이터 할때 어케하는건데!?


https://www.educba.com/mutable-vs-immutable-java/

일단 정의 부터 알아보자!

불변 객체란?

객체가 한 번 생성되면 그 상태를 변경할 수 없는 객체이다.

대표적인 예: String, Integer, LocalDate 등.

불변 객체의 장점

  • 안정성과 스레드 안전성
    • 상태가 변하지 않으므로 여러 스레드에서 동시에 사용해도 안전하다.
    • 추가적인 동기화 없이 읽기 전용 데이터로 활용할 수 있다.
    • 예: String은 여러 스레드에서 공유될 때 안전하게 사용할 수 있음.
  • 설계
    • 상태가 변하지 않으므로 객체의 상태를 추적하거나 변경을 고려할 필요가 없다.
    • 디버깅과 유지보수가 더 쉬워진다.
  • 해시 기반 컬렉션과의 호환성
    • HashMap이나 HashSet 같은 컬렉션에서 불변객체를 키로 사용할 때, 객체 상태가 변경되지 않으므로 안정적으로 동작한다.
    • 가변객체를 키로 사용할 경우 상태가 변하면 해시 값이 변경되어 예상치 못한 동작을 초래할 수 있다.
  • 불변성 보장
    • 객체의 상태를 신뢰할 수 있으므로 외부에서 상태를 변경할 수 없다는 점에서 보안적 장점이 있다.
    • 예: 데이터베이스 쿼리 결과나 설정값 같은 변경 불가능한 데이터를 표현할 때 적합.
  • 캐싱 및 재사용
    • 불변객체는 상태가 변하지 않으므로 캐싱하거나 공유하여 성능을 향상시킬 수 있다.
    • 예: Integer.valueOf() 메서드는 -128 에서 127 범위의 숫자를 캐싱하여 동일한 객체를 재사용.

가변 객체란?

객체가 생성된 후에도 상태를 변경할 수 있는 객체이다.

대표적인 예: StringBuilder, ArrayList, HashMap

가변객체의 장점

  • 성능 최적화
    • 데이터가 자주 변하는 경우, 가변객체는 새 객체를 생성하지 않고 상태를 변경하므로 메모리와 CPU 자원을 절약할 수 있다.
    • 예: StringBuilder는 문자열 연산이 빈번할 때 String보다 효율적.
  • 유연성
    • 가변객체는 상태를 변경할 수 있으므로 다양한 로직을 구현할 때 유연하게 사용할 수 있다.

상태 변경?

객체의 필드 값(데이터)이 수정되는 것을 의미한다.

  1. 객체 내부에 필드 값이 있다.
  2. 객체가 제공하는 메서드(Setter, Modifier)등을 사용해 필드 값을 수정할 수 있다.
class Person {
    private String name;
    private int age;

    // 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Getter
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    // Setter
    public void setName(String name) {
        this.name = name; // 상태 변경
    }

    public void setAge(int age) {
        this.age = age; // 상태 변경
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 25);
        System.out.println(person.getName()); // Alice
        System.out.println(person.getAge());  // 25

        // 상태 변경
        person.setName("Bob");
        person.setAge(30);

        System.out.println(person.getName()); // Bob
        System.out.println(person.getAge());  // 30
    }
}

설명

  1. Person 클래스의 필드 name과 age는 객체의 상태를 나타낸다.
  2. 객체 생성 후, setName()과 setAge() 메서드를 호출하면 내부 상태가 변경된다.
    • 처음엔 "Alice", 25 였으나 "Bob", 30 으로 변경됨.

⚠️여기서 질문!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Q:
Person 클래스의 name은 불변 객체인 String으로 되어있는데 setName()으로 변경을 한다 해도 결과적으로 불변객체인 String name을 바꾸는거 아니냐고!!!

A:
setName() 메서드로 변경된다고 해서 기존 String 객체 자체가 변경되는 것은 아니다! 이걸 이해하려면 객체 참조와 메모리 구조를 좀 살펴봐야한다!

 

질문: setName()으로 변경 시 무슨 일이 일어나는거야??
public void setName(String name) {
    this.name = name; // 상태 변경
}​

 

setName() 메서드는 this.name 필드의 참조를 다른 String 객체로 교체하는 것이다. 기존의 String 객체는 변경되지 않고 그대로 유지된다.

과정:
1. String은 불변객체이기 때문에, 이미 생성된 String 객체는 그 내용이 절대 바뀌지 않는다.
2. 대신, setName() 메서드는 this.name이 새로운 String 객체를 참조하도록 변경하는 것 이다.

메모리 구조:
1. "Alice"라는 String 객체는 그대로 메모리에 남아 있고, this.name은 이제 "Bob"이라는 새로운 String 객체를 참조한다.
2. 기존의 "Alice"는 변경되지 않으며 더 이상 참조되지 않는다면 가비지 컬렉터에 의해 정리된다.

정리: 
1. 불변 객체의 특징:
- 불변객체는 한 번 생성되면 상태를 변경할 수 없다.
- setName()은 기존 String 객체를 변경하는 것이 아니라, name 필드가 다른 String 객체를 참조하도록 만든다.
2. 객체 참조의 개념:
- name 필드는 단순히 String 객체를 가리키는 참조(reference)이다.
- setName()은 name 필드가 다른 String 객체를 가리키도록 "참조"를 변경 한다.

진짜 찐찐찐 최종 정리:
setName() 메서드는 가변객체를 만드는 수단 이고, 가변 객체는 Person 클래스의 객체이다.

불변 객체 vs 가변 객체

특성 불변 객체 가변 객체
상태 변경 불가능 가능
스레드 안정성 기본적으로 스레드 안전 동기화 필요
메모리 사용 새 객체 생성으로 메모리 사용 증가 가능 상태 변경으로 메모리 사용 효율적
사용 예 읽기 전용 데이터, 멀티스레드 환경 데이터 변경이 빈번한 경우

 

불변 객체를 사용해야하는 경우

  • 멀티스레드 환경에서 안전한 데이터 공유가 필요할 때.
  • 해시 기반 자료구조에서 키로 사용할 객체일 때.
  • 읽기 전용 데이터(예: 설정, 상수, 불변의 엔티티)를 다룰 때.
  • 함수형 프로그래밍 패턴이나 데이터 불변성을 중시하는 설계가 필요할 때.

그렇구나! 이제 알겠다. 이제 정말 많은걸 깨달았다. 불변객체랑 가변객체가 이런거구나~

 

 

** 그냥 하루하루 개인 공부한 것을 끄적 거리는 공간입니다.

이곳 저곳에서 구글링한 것과 강의 들은 내용이 정리가 되었습니다.

그림들은 그림밑에 출처표시를 해놓았습니다.

문제가 될시 말씀해주시면 해당 부분은 삭제 하도록하겠습니다. **

반응형

댓글