들어가며
프로그래밍에서 불변 객체란 무엇인가요? 라고 듣는 다면 뭐라고 답할 수 있을까
변하지 않는 객체, 원시타입입니다. 라고 까지밖에 대답을 할 수 없었고 객체에 대한 문자열화를 하지 않는다면 메모리 주소값을 내놓는 자바를 복습하고 있기 때문에 이것이 얕은 복사, 깊은 복사까지와도 이어지기 때문에 이제 정리를 할 때가 왔다고 생각했다.
JS와 JAVA를 나누어가며 정리해본다.
가변(variable)이란
사물의 모양이나 성질이 바뀌거나 달라질 수 있음.
불변(constancy)이란
사물의 모양이나 성질이 변하지 아니함. 또는 변하게 하지 아니함.
사전적 정의를 알고 영어로는 어떻게 표현되는지 알고 들어가면 이해가 조금 더 쉬워질것 같다.
JS에서 변수 선언할때 var, const가 왜 이런 이름을 가지고 있는지 알 수 있다.
프로그래밍에서 데이터 타입을 둘로 나눈다면 기본형(primitive type)과 참조형(reference type)으로 나눌 수 있다.
기본형
기본형이란 바로 값을 그대로 할당
값을 초기화하는 변수에 그대로 값이 저장된다.
만약 A라는 변수에 1을 저장한다면 A는 1이라는 값을 할당받아 값을 그대로 가지고 있게된다.
Stack | 데이터 영역 | |
---|---|---|
변수명 | A | |
주소 | 01 | @011 |
참조 | @011 | |
데이터 | 1 |
참조형
참조형이란 값이 저장된 주소값을 할당(참조)한다
값을 초기화하는 변수에 해당 값에 대한 메모리 주소를 저장한다.
만약 A라는 변수에 new Map()이라는 값을 준다면 메모리 힙에 Map이 생성된다.
생성이 된후에 A는 스택에서 메모리 힙에 올라가 있는 Map의 메모리 주소 값을 참조한다.
조금 더 자세히 들어가면 A의 주소는 01, 힙에 생성된 Map의 주소는 11이라고 한다.
힙에 있는 객체는 주소, 데이터를 가지고 있고 스택에 있는 A는 01이라는 주소와 자료형만 가지고 있다.
Stack | 데이터 영역 | Heap | |
---|---|---|---|
변수명 | A | ||
주소 | 01 | @011 | @m111 |
참조 | @011 | @m111 | |
데이터 | Map |
JS에서
기본형은 Number, String, Boolean, null, undefined, Symbol
참조형은 객체(function, Map, Set, Array...)
JAVA에서
기본형은 boolean, char, 정수(byte, short, int, long), 실수형(float, double)
참조형은 String, 배열, 열거(enum), 클래스(class), 인터페이스(interface)
기본형과 참조형의 개념은 둘이 똑같지만 종류가 다르다.
동적 언어와 정적 언어의 차이점이다.
동적 언어인 JS는 변수에 대한 타입을 강제하지 않는다.
선언을 할때 const, let과 같은 선언문을 사용한다. 어떤 값이 들어오더라도 유연하게 받아드리고 변수를 선언하는 순간 메모리에 올라가기 때문에 null, undefined 이든 뭐든 상관이 없다.
또한 string이 기본형이기 때문에 아래와 같은 것이 가능하다.
let a = "abc";
let b = "abc";
console.log(a===b); // true
console.log(a==="abc"); // true
정적 언어인 JAVA는 변수에 대한 타입을 강제한다.
선언을 할때 부터 메모리 영역을 주기 위해 자료형을 사용한다. 어떤 값이 들어오는지 정확하게 파악하고 만약 선언한 자료형에 위반하는 값을 할당한다면 디버그때 주의를 준다.
java에서 string은 class인 참조형이다.
따라서 다양한 method도 존재한다.
String a = new String("abc");
String b = new String("abc");
System.out.print(a==b); // false
System.out.print(a==new String("abc")); // false
System.out.print(a.equal(b)); // true
java와 js의 string의 차이점으로 기본형과 참조형의 차이를 쉽게 이해할 수 있었다.
결국 객체도 관리하는 장소가 다르지만 데이터를 메모리 영역에 저장하는 것이기 때문에 객체 자체도 원시타입과 같이 값 자체를 저장하는 것과 같다.
따라서 원시 타입과 같이 다른 값을 대입한다면 객체 내의 데이터는 다른 값으로 초기화가 가능하기 때문에 가변적이라 할 수 있다.
const arr = new Array(1,2,3);
abc[1] = '3';
console.log(arr); // [1,'3',3]
const map = new Map();
map.set('a','a');
console.log(map.get('a')); // 'a'
> map.set('a', 'c');
console.log(map.get('c')); // 'c'
JS는 원시 타입 이외의 값을 가변값으로 본다.
JAVA는 ArrayList, HashMap, StringBuilder, StringBuffer 등이 존재한다.
불변 객체란 재할당은 가능하지만 객체 생성 이후 내부의 상태가 변하지 않는 객체
내부의 값을 마음대로 수정이 불가능하다.(read-only)
만약 할당되어 있는 값을 바꾸고 싶다면 재할당을 사용한다.
let a = "abc";
a += "c";
console.log(a); // "abcc"
JS는 원시타입을 불변값으로 본다.
JAVA는 대표적으로 String이 있고 class를 폐쇄적(final, setter(x)...)으로 만든다면 그것이 곧 불변값이 된다.