java의 클래스들을 뜯다 보면, final 이라던지, static final과 같은 키워드가 생각보다 자주 보인다는 것을 알 수 있어요. 특히, String은 이 키워드가 상당히 많이 붙어있습니다. 이것은 무엇을 하는 것일까요? 한 번 값이 정해지면 그 값을, 수정할 수 없게 만드는 것입니다. 언제 정해질 수 있을까요? 메모리에 올라갈 때. 한 가지 예를 들어보겠습니다.

 

 


 String 클래스 안에는 final 필드인 value가 있습니다. 이것은 문자열의 실제 내용을 저장하기 위한 char형 배열입니다. 이것은 언제 값이 정해지나요?

 

 

 생성자에서 초기화를 할 때 값이 정해집니다. String 객체 a를 새로 생성해 봅시다.

 

 

  그러면, 생성자가 호출이 되고, 152 ~ 153번째 줄이 끝나고 나면, val의 "abc"를 가리킵니다. 그 이후에, a의 val이 변경이 될 수 없습니다. 이미, val 값이 assign이 되었기 때문입니다.

 

 

 즉, val이 "abc"를 가리키고 있었는데, 나중에 "abf"를 가리키지 못합니다. 한 번 값이 정해지고 나면 바꿀 수 없기 때문입니다.

 

 

 그러면 이 코드는 어떨까요? 필드 arr이 final로 선언이 되어 있으니, 배열의 내용을 변경하는 upd 함수는 에러가 나야 할 거 같습니다. 하지만, arr은 참조형입니다. 단지, 배열을 가리키는 필드일 뿐입니다.

 

 

 Obj 객체가 새로 생성되었다고 해 봅시다. 그러면 메모리에 아래와 같이 들어가 있을 겁니다. 그 다음에, 문제의 upd 메서드를 호출하면, arr[lo] = x로 바꾸라고 되어 있어요. 그 말인 즉슨, arr의 lo번째 원소를 x로 바꾸라는 의미입니다. lo = 1이라고 하고, x = 5라고 해 봅시다. 

 

 

 바꾸는 대상이 배열의 원소이지, arr이 가리키는 공간이 아닙니다. 따라서, 의도대로 잘 수행이 됩니다.

 

 


 왜, String의 value는 앞에 static을 붙이지 않았을까요? 관례상 final 앞에 static을 붙인다는데. 붙이지 않는 경우도 있을까요? 사실, 이것은 '관례'라는 키워드를 깨고 보면 생각보다 어렵지 않게 이해할 수 있습니다. String 객체는 객체마다 공통된 문자열을 저장해야 할까요?

 

 

 항상 그래야만 할까요? 아닙니다. 어떤 String 객체는 "chogahui" 라는 문자열을 담을 수 있고, 어떤 String 객체는 "maltize" 라는 문자열을 담을 수도 있습니다. 무조건 공통적으로 "abcd" 라는 char형 배열을 담아야 되는 것은 아닙니다.

 

 

 따라서, static을 붙이지 않습니다. 클래스 String의 인스턴스들이 항상 같은 문자열 내용을 담고 있어야 되는 건 아니거든요. 오히려 부자연 스럽습니다. 정리를 하자면, 초기화 이후에 값이 변경되지 않아야 하지만, 인스턴스마다 값이 달라야 하는 경우에는 final만 붙입니다. 초기화 이후에 값이 변경되지 않으면서, 각 Class의 인스턴스마다 공통된 값을 가져야 할 경우, final 앞에 정적이라는 것을 뜻하는 static을 붙이는 것을 고려합니다.

 

 예를 들어서, 어떠한 Object 인스턴스들이 항상 같은 width와 height를 가져야 한다고 한다면..

 

 

 width와 height 앞에 static을 붙이는 것을 고려합니다. 그러면 Obj 인스턴스 a와 b의 width와 height는 별개의 공간이 아닌, Obj class 안에 있는 width와 height를 끌고 옵니다.

 

 

 다음에, static 키워드를 붙인 필드 width와 height에 final을 붙입니다. 이는 초기화 작업을 한 후에 width나 height의 값이 변경되지 않음을 의미합니다. 그러면 Obj 클래스에서 width와 height는 고정된 값을 가지고 쓸 수 있는 것입니다.

 

 

 당연하게도, final static으로 선언된 필드는 생성자에서 초기화가 될 수 없는데요. arr이라는 필드가 올라가는 시점은, 클래스를 로드할 때이지, instace가 생성되는 시점이 아니기 때문입니다. 이미 인스턴스가 생성되고, 생성자를 호출한 시점에서는, 이미 arr이라는 정적 필드는 초기화가 되어 있습니다. final 키워드는 초기화 후에, 값을 변경하지 못하게 하기 때문에, 10번째 줄에서 arr = 5; 문장은 오류가 날 수 밖에 없습니다.