-
Java mutable 과 immutableJAVA 2023. 10. 8. 23:06
Mutable 과 Immutable
Java에는 가변(mutable)객체와 불변(immutable)객체가 존재한다.
가변 객체는 힙 영역에 생성된 객체를 변경할 수 있는 객체이고 불변 객체는 반대로 힙 영역에 생성된 객체를 변경할 수 없는 객체이다. 대표적인 불변 객체인 String 으로 예시를 보면 다음과 같다.String val1 = "abc"; System.out.println("val1 initial " + System.identityHashCode(val1)); val1 += "xyz"; System.out.println("val1 after "+System.identityHashCode(val1)); // output val1 initial 1435804085 val1 after 1798286609
위와 같이 val1이라는 String 을 선언하고 처음 "abc"로 초기화 한 후에 hascode를 출력해보고 val1에 "xyz"를 추가해준 뒤 다시 한번 hashcode를 출력해보았다. 결과로 나온 output은 두개가 서로 다른 값을 출력하고있다. String은 불변 객체이기에 새로 "abcxyz"라는 String을 생성한 것이다.
Immutable Class
불변 객체를 생성하기위한 규칙은 다음과 같다.
- 모든 필드를 private,final로 선언한다.
- class를 final로 선언한다
- setter method를 제공하지 않는다.
- 참조에 의해 변경 가능성이 있는 경우 방어적 복사를 이용하여 전달한다.
- 객체 생성을 위한 생성자 or 정적 팩토리를 추가한다.
Immutable Class 만들기
public class Immutable { public int val; public List<String> list; public Immutable(int val, List<String> list){ this.val = val; this.list = list; } public int getVal(){ return val; } public List<String> getList(){ return list; } }
위와같은 class 를 Immutable class로 바꾸어보자.
Immutable immutable = new Immutable(0,new ArrayList<>()); System.out.println(immutable.getVal()); System.out.println(immutable.getList()); immutable.val = 10; System.out.println(immutable.getVal()); // output 0 [] 10
현재는 위처럼 객체를 하나 만들고 내부 값을 변경시킬 수 있다.
public final class Immutable { private final int val; private final List<String> list; public Immutable(int val, List<String> list){ this.val = val; this.list = list; } public int getVal(){ return val; } public List<String> getList(){ return list; } }
우선 내부 필드들을 private final로 수정했다. 이럴경우 위의 예시의 immutable.val 처럼 접근하여 값을 바꾸는것은 불가능해진다.
Immutable immutable = new Immutable(0,new ArrayList<>()); List<String> list = immutable.getList(); System.out.println(immutable.getList()); list.add("hello"); System.out.println(immutable.getList()); // output [] [hello]
하지만 위의 예시처럼 list같은경우 reference를 참조히기때문에 여전히 내부 값을 수정할 수 있다. 이를 해결하기 위해 방어적 복사를 이용하여 getList를 수정해보자.
public List<String> getList(){ return new ArrayList<>(list); }
getList에서 반환되는 List를 새로 생성하여 반환해 주었다.
ArrayList<String> initList = new ArrayList<>(); initList.add("hello"); Immutable immutable = new Immutable(0,initList); List<String> list = immutable.getList(); System.out.println(immutable.getList()); list.add("world"); System.out.println(immutable.getList()); System.out.println(list); // output [hello] [hello] [hello, world]
getList에서 List를 새로 생성해서 반환했기때문에 immutable.getList() 한 list에 새로 값을 넣어도 내부 값은 변경되지 않았다. 하지만 list.add("world") 처럼 받아온 list에 값은 추가가 되는데, getList를 다음과 같이 변경하면 받아온 list에서의 값 변경도 불가능하게 한다.
public List<String> getList(){ return Collections.unmodifiableList(list); }
'JAVA' 카테고리의 다른 글
Spring Boot AOP를 이용해 로그인 검증하기 (0) 2024.07.29 Spring Boot MessageConverter (0) 2024.06.24 Java와 일급 함수 (0) 2023.09.18 Java Generic Compile 동작 (0) 2023.09.11 JVM Memory Area (0) 2023.09.08