class 안에는 여러 가지 필드들이 있습니다. 그 중에 static이 붙은 것도 있고, 아닌 것도 있을 겁니다. 클래스 안에 static으로 선언된 것들을 Java에서는 클래스 변수라고 이야기를 합니다. 설계자 분들이 요 키워드를 대체 어떤 기준으로 붙였을까요? 예제 프로그램을 봅시다.
My_Obj에는 2개의 필드가 있습니다. 하나는 iv, 다른 하나는 cv입니다.
먼저 My_Obj 객체 a를 생성합니다. 그리고 a.iv에 2를, a.cv에 1을 넣습니다. 그 다음에 a의 필드 값들을 출력하고 있어요. 다음에, b를 생성하고 b.iv와 b.cv에 각각 5, 5를 넣고 b의 필드 값들을 출력하고 있습니다. 그 다음에 다시, a의 필드 값들을 print 하고 있어요. 그러면 출력 결과가 어떻게 나올까요?
크게 3가지 영역으로 나누어서 봅시다. stack, heap, 그리고 메소드 영역. 이 중에서, 클래스 변수는 클래스 파일을 읽어들이고 로더가 올릴 때, 메모리에 올라갑니다. 그리고 프로그램이 종료될 때 사라집니다. 힙에 있는 객체들은, 가비지가 되었을 때, gc가 가비지를 수거할 때 사라집니다. 그리고 지역 변수는 자신이 선언된 블록이 끝났을 때 사라지는 것과 비교하면 다른 점이 명확합니다.
그러면 메모리 상에 요렇게 My_Obj의 cv가 올라갈 거에요. 다음에 10번째 줄을 수행해 봅시다.
그러면 메모리 상에 이런 식으로 올라가겠군요. 그 다음에 a.cv에 1을, a.iv에 2를 넣으라고 했습니다.
그러니, 일단 요래 저장이 될 것이고, 실제로 a.iv와 a.cv를 출력하면 각각 2와 1이 나옵니다.
다음에 또 다른 객체를 생성해서, 그 객체를 b가 가리키게 하였습니다. 그러면 메모리 상에 이렇게 올라갈 건데요. 중요한 것은 cv라는 필드는 클래스 변수입니다. 즉, a.cv로 접근해도, b.cv로 접근해도 같은 공간에 접근해 버리게 됩니다. 그러면 b.cv에 5를 넣어볼까요?
그러면 method 영역에 있었던 cv의 값이 5로 갱신됩니다.
다음에 b.iv에 5를 넣습니다. a.iv와 b.iv는 별개의 공간에 있기 때문에, a.iv의 값이 5로 갱신되지 않습니다. 대신 b.iv의 값이 5가 됩니다. 그러면 b의 필드값을 출력했을 때 5 5가 나올 겁니다. 그 다음에 a의 필드값인 iv와 cv를 차례대로 출력하면 어떤 값이 나올까요?
iv값은 2가, cv값은 5가 나올 겁니다. 이는, b.cv = 5 때문에, cv 필드가 5로 업데이트가 되어버렸기 때문입니다.
실행 결과는 위와 같습니다.
그러면 언제 쓰느냐가 문제가 될 수 있습니다. 좋은 예제가 있을까요? 우리가 Collection 중에서 제일 익숙한 ArrayList 클래스의 내부를 뜯어보시면, DEFAULT_CAPACITY라는 값이 10으로 선언이 되어 있다는 것을 볼 수 있어요. 그리고, 이 것은 static으로 선언이 되어 있습니다. 왜 그렇게 해 놓았을까요?
이런 식으로 선언해 버리면, ArrayList 객체를 생성했을 때, 공통적으로 default 용량을 10으로 줘 버리게 됩니다. 굳이, 인스턴스 필드로 둘 이유가 없습니다. 보통 동적 배열을 선언할 때, 디폴트 초기 용량 값은 10, 16 이런 식으로 주는데요. 이러한 값들을 ArrayList 객체 모두에게 공통적으로 적용을 시킬 수 있습니다.
즉, 동적 배열이 생성되었을 때, value의 초기 크기를 10으로 줄 거다. 라는 것은 ArrayList 객체들이 가져야 하는 공통 특성이기 때문에 static으로 뺄 수 있어요.
그래서 클래스 파일을 읽을 때, 이 값을 메모리에 올려놓고, method 영역에 접근해서 쓰는 것입니다. 그런데, value를 static으로 선언했다면 어떨까요?
그러면 ArrayList 객체 a, b가 있을 때 a.value가 가리키는 배열과 b.value가 가리키는 배열이 같을 겁니다. a에 1이라는 원소를 추가했습니다.
그러면 이렇게 될 거에요. 그런데 b에 2라는 원소를 추가했어요. 그러면 실제로는 a.value가 있는 메모리 공간과, b.value가 있는 메모리 공간이 같기 때문에, 얘네들이 가리키는 배열 또한 같습니다. 그러면, 2가 추가될 거에요.
그러면 ArrayList a를 모두 순회하면 어떤 결과가 나올까요? 1, 2가 나올 거에요. 우리가 원하는 것은 a에는 1만 추가했으니까 1만 나오고, b에는 2만 추가했으니까 b를 순회하면 2만 나오는 것인데, 실제로는 그렇지 않았습니다. 즉, 동적 배열 객체에서, 실제로 추가한 데이터들을 저장하고 있는 배열인 value는, static으로 선언하면 안 됩니다. 같은 특성을 가지면 안 되는 것은 필드 앞에 static을 붙이지 않는다. 정도 보시면 되겠습니다.
'코딩 > Java' 카테고리의 다른 글
java for each 문은 arrayList에서 어떻게 동작할까? (14) | 2019.09.12 |
---|---|
java wrapper 클래스 : 기본 타입을 포장한다. (2) | 2019.08.29 |
java 1차원, 2차원 배열 : 간단한 예제를 보고 배워봅시다. (4) | 2019.08.09 |
java string intern 메서드 : pool이 된다는 것만 기억합시다. (2) | 2019.08.08 |
cp949 vs euc-kr : 어떤 차이점이 있는지 간단히 알아봅시다. (0) | 2019.08.04 |
최근댓글