반응형

 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을 붙이지 않는다. 정도 보시면 되겠습니다.

반응형

댓글을 달아 주세요

  1. 한번사는인생.

    다 읽지 않은 상태에서 궁금한게 있습니다.
    class 는 참조형이기때문에 저는 heap에 저장되는걸로 알고 있었는데 아닌가요?
    클래스 변수(a, b)는 stack에 저장(heap의 주소값)이 되는건가요?

    • 코딩강아지
      2019.08.22 17:41 신고

      My obj a = new My_obj();
      이 부분이면 a는 지역변수이고요.
      a가 객체를 가리키는 식이고요..
      이게 주솟값을 저장하는지는 정확히는 모르겠지만
      참조하는 건 맞아보입니다.

    • 한번사는인생.
      2019.08.22 17:43 신고

      지역/전역 변수에 상관없이
      참조형 데이터는 heap에 저장되는걸로 알고 있습니다. 한번 찾아봐야겠어요.ㅎㅎ

    • 코딩강아지
      2019.08.22 17:48 신고

      정확히 어디인지는 헷갈리긴 하네요.
      제가 보는 교재에는 static 필드가
      method area에 저장된다고 나오기는 합니다.

      요새 Jvm은 어떨지는 잘 모르겠네요.
      예전에 리터럴은 가비지 수집 대상이 아니였는데..
      어느 순간 바뀌었다는 야기도 있고요..

      JVM 메모리 구조도 언젠가는..

  2. What should I do?

    그 놈의 주소값

  3. 익명

    비밀댓글입니다

  4. 베스트터치

    잘 보고 갑니다 ^^

  5. 곰곰지영

    오...어려워요...힝 ㅋㅋ :)

  6. 심플한 개발자

    static 변수는 메서드 영역에 올라가는 것이 맞습니다. 그래서 static 변수는 인스턴스를 생성하지 않아도 접근할 수 있죠. 클래스를 통해 만든 인스턴스가 힙에 저장되고요. 좋은 내용을 잘 정리해주셨네요.

  7. 상식체온

    이번 포스팅도 사용하고 싶은 영어가 많네요.
    좋은 하루되세요.

  8. H_A_N_S

    코딩 잘 하시는 분 넘 부러워요. 오늘도 즐거운 하루 되세요ㅎ

  9. 코드사냥꾼

    안그래도 변수의 메모리 저장이 이해가 더뎠는데 한번에 이해가 갔어요 ..! 좋은 정보 감사합니다 ㅎㅎ

  10. dddd

    요거 퍼가도될까요 ??? 개인 notion에 저장해놓고 볼려고 해요