개요
자바의 클래스는 mutable과 immutable 2가지가 존재합니다. 2개의 차이점을 알아보겠습니다.
mutable과 immutable
사전의 의미를 먼저 확인해보겠습니다. mutable은 '변할 수 있는', immutable은 '변경할 수 없는, 불변의'의 뜻을 가지고 있습니다. 이를 Java 관점에서 본다면 mutable 객체는 초기화 된 이후 '변할 수 있는' 객체이고, immutable 객체는 초기화된 이후 '변경할 수 없는' 객체입니다.
mutable
mutable 객체는 초기화 된 이후에 필드, 상태 등 값을 변경할 수 있습니다. 새로운 객체가 생성되는 것이 아니고 현재 객체의 값을 변경합니다. mutable 객체들은 getter와 setter 사용이 가능합니다.
- Java.util.Date
- StringBuilder
- StringBuffer
immutable
immutable 객체는 초기화 된 이후에 변경 할 수 없습니다. 따라서 getter 메서드만 사용이 가능하고 setter는 제공되지 않습니다.
- 원시 타입(int, long, float, double)
- legacy 클래스(HasTable, Stack, Dictionary, Properties, Vector)
- Wrapper 클래스(Boolean, Byte, Short, Integer, Long, Float, Double...)
- String 클래스
많은 개발자들은 객체 값 수정 대신 새로운 객체 생성에 부담을 느끼고 불변 객체를 잘 사용하지 않습니다. 하지만 가비지 컬렉터가 더이상 사용하지 않는 객체를 알아서 정리해주고 가변 객체의 손상을 보호하는 코드를 제거할 수 있다는 측면에서는 긍정적입니다. 또한 동시성에 강력합니다. 상태나 값이 변경되지 않기 때문에 여러 쓰레드의 인터럽트와 동시 작업에도 전혀 문제가 없습니다. (Oracle - Immutable Objects)
자바를 사용하는 개발자라면 객체 인스턴스의 내부 값을 변경하였더니, 내가 원치 않던 곳까지 값이 같이 변경된 경험이 있을 겁니다. 다른 곳들이 해당 인스턴스 참조변수의 주소값을 공유하기 때문인데요. 사실 수정 당시에 다른 곳에서도 쓰이고 있는지 몰랐을 겁니다. 실제로 해당 인스턴스가 어디에 얼마나 쓰이는지 모두 찾기란 쉽지 않습니다. 이런 방식의 코드는 유지보수를 어렵게 만듭니다. 혹시 지금 내가 수정하는 값이 얼마나 큰 사이드 이펙트를 일으킬지 모르기 때문입니다. 이 문제를 막을 수 있는 방법은 애초에 객체를 불변 상태로 만드는 것입니다. 그런데 값 변경이 필요한 경우에는 어떻게 할까요? 특정 값을 변경하고자 한다면 아예 새로운 객체를 만들어서 반환하면 됩니다. 대신, 새로운 객체를 반환하다보니 꼭 반환 값을 받아야 합니다. (물론 변경 가능성이 높은 경우나 상황에 따라 불변 객체를 사용하지 않을 수 있습니다.)
mutable | immutable | |
값 수정 | 초기화 이후 객체 값 수정 가능 | 초기화 이후 객체 값 수정 불가능 |
상태 변경 | 상태 변경 가능 | 상태 변경 불가능 |
새로운 객체 생성 | 값 수정이 가능하므로 새로운 객체를 만들지 않음 | 값 수정이 불가능하므로 값 변경이 필요하면 아예 새로운 객체를 생성함 |
setter | setter 메서드 가능 | setter 메서드 불가능 |
thread-safe | 경우에 따라 thread-safe 가능하지만 불가능한 경우도 있음 | thread-safe |
mutable을 immutable하게 만들기
mutable한 JtpExample 클래스 입니다. immutable한 클래스로 만들기위해 직접 바꿔보시기 바랍니다.
public class JtpExample {
private String s;
JtpExample(String s) {
this.s = s;
}
public String getName() {
return s;
}
public void setName(String coursename) {
this.s = coursename;
}
public static void main(String[] args) {
JtpExample obj = new JtpExample("JavaTpoint");
System.out.println(obj.getName());
//setMethod를 사용하여 name을 "변경" 할 수 있습니다.
obj.setName("Java Training");
System.out.println(obj.getName());
}
}
immutable한 클래스로 만들기 위해서 다음 조건을 충족해야 합니다.
- final class로 만들면 상속 할 수 없습니다.
- 모든 필드를 private으로 만들어 외부에서 직접 접근을 막습니다.
- setter 함수를 제거합니다.
- 모든 mutable 필드를 final로 만들어 한번 초기화되면 더이상 수정되지 못하도록 합니다.
public final class JtpExample {
private final String s;
JtpExample(final String s) {
this.s = s;
}
public final String getName() {
return s;
}
public static void main(String[] args) {
JtpExample obj = new JtpExample("Core Java Training");
System.out.println(obj.getName());
}
}
String
자바에서 String 값을 변경하는 것은 사실 새로운 String을 만드는 행위입니다. 아래와 같이 변수 first는 변경에 따라 주소값이 바뀝니다. 이는 String이 immutable해서 새로운 String이 만들어져서 복사 되었기 때문입니다.
String first = "first";
System.out.println(first.hashCode());
// prints something
first = first + "!";
System.out.println(first.hashCode());
// different string, different hash code
String 클래스가 immutable인 이유는 어디에나 많이 사용되기 때문에 성능을 향상시키고 보안을 강화하기 위해서입니다.
참고
'학습 > Java' 카테고리의 다른 글
Entity vs Value Object 차이점 (0) | 2023.06.30 |
---|---|
스프링 AOP (1) - 동적 프록시 (0) | 2023.01.11 |
StringBuffer vs StringBuilder (0) | 2022.11.01 |
Java 8에 등장한 Optional이란? (0) | 2022.10.29 |
자바 8에 추가된 Date Time API (0) | 2022.10.28 |