반응형
음 String은 불변이고 StringBuffer 랑 StringBuilder는 가변이래 알겠어 알겠는데 그래서 구조랑 뭐 데이터 할때 어케하는건데!?
일단 정의 부터 알아보자!
불변 객체란?
객체가 한 번 생성되면 그 상태를 변경할 수 없는 객체이다.
대표적인 예: String, Integer, LocalDate 등.
불변 객체의 장점
- 안정성과 스레드 안전성
- 상태가 변하지 않으므로 여러 스레드에서 동시에 사용해도 안전하다.
- 추가적인 동기화 없이 읽기 전용 데이터로 활용할 수 있다.
- 예: String은 여러 스레드에서 공유될 때 안전하게 사용할 수 있음.
- 설계
- 상태가 변하지 않으므로 객체의 상태를 추적하거나 변경을 고려할 필요가 없다.
- 디버깅과 유지보수가 더 쉬워진다.
- 해시 기반 컬렉션과의 호환성
- HashMap이나 HashSet 같은 컬렉션에서 불변객체를 키로 사용할 때, 객체 상태가 변경되지 않으므로 안정적으로 동작한다.
- 가변객체를 키로 사용할 경우 상태가 변하면 해시 값이 변경되어 예상치 못한 동작을 초래할 수 있다.
- 불변성 보장
- 객체의 상태를 신뢰할 수 있으므로 외부에서 상태를 변경할 수 없다는 점에서 보안적 장점이 있다.
- 예: 데이터베이스 쿼리 결과나 설정값 같은 변경 불가능한 데이터를 표현할 때 적합.
- 캐싱 및 재사용
- 불변객체는 상태가 변하지 않으므로 캐싱하거나 공유하여 성능을 향상시킬 수 있다.
- 예: Integer.valueOf() 메서드는 -128 에서 127 범위의 숫자를 캐싱하여 동일한 객체를 재사용.
가변 객체란?
객체가 생성된 후에도 상태를 변경할 수 있는 객체이다.
대표적인 예: StringBuilder, ArrayList, HashMap
가변객체의 장점
- 성능 최적화
- 데이터가 자주 변하는 경우, 가변객체는 새 객체를 생성하지 않고 상태를 변경하므로 메모리와 CPU 자원을 절약할 수 있다.
- 예: StringBuilder는 문자열 연산이 빈번할 때 String보다 효율적.
- 유연성
- 가변객체는 상태를 변경할 수 있으므로 다양한 로직을 구현할 때 유연하게 사용할 수 있다.
상태 변경?
객체의 필드 값(데이터)이 수정되는 것을 의미한다.
- 객체 내부에 필드 값이 있다.
- 객체가 제공하는 메서드(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
}
}
설명
- Person 클래스의 필드 name과 age는 객체의 상태를 나타낸다.
- 객체 생성 후, 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 가변 객체
특성 | 불변 객체 | 가변 객체 |
상태 변경 | 불가능 | 가능 |
스레드 안정성 | 기본적으로 스레드 안전 | 동기화 필요 |
메모리 사용 | 새 객체 생성으로 메모리 사용 증가 가능 | 상태 변경으로 메모리 사용 효율적 |
사용 예 | 읽기 전용 데이터, 멀티스레드 환경 | 데이터 변경이 빈번한 경우 |
불변 객체를 사용해야하는 경우
- 멀티스레드 환경에서 안전한 데이터 공유가 필요할 때.
- 해시 기반 자료구조에서 키로 사용할 객체일 때.
- 읽기 전용 데이터(예: 설정, 상수, 불변의 엔티티)를 다룰 때.
- 함수형 프로그래밍 패턴이나 데이터 불변성을 중시하는 설계가 필요할 때.
그렇구나! 이제 알겠다. 이제 정말 많은걸 깨달았다. 불변객체랑 가변객체가 이런거구나~
** 그냥 하루하루 개인 공부한 것을 끄적 거리는 공간입니다.
이곳 저곳에서 구글링한 것과 강의 들은 내용이 정리가 되었습니다.
그림들은 그림밑에 출처표시를 해놓았습니다.
문제가 될시 말씀해주시면 해당 부분은 삭제 하도록하겠습니다. **
반응형
'public void static main > Java' 카테고리의 다른 글
[Spring Security] Spring Security에 대해서 알아보자! (0) | 2025.01.13 |
---|---|
[Spring] Filter, AOP, Interceptor 그리고 Middleware (0) | 2025.01.02 |
[JAVA] LinkedList 알꺼같으면서도 모르겠다. (0) | 2024.12.23 |
[JAVA] 타입 캐스팅 시 발생하는 오버플로우? (0) | 2024.12.22 |
[JAVA] JVM Memory (0) | 2022.02.18 |
댓글