pungjoo

Static final fields(primitive or String type) 사용 주의 본문

분류없음

Static final fields(primitive or String type) 사용 주의

pungjoo.kim 2012.04.23 11:25

’Foo.class’에 상수를 정의하고 'Bar.class’에서 ‘Foo.class’에서 정의한 상수를 사용하고 있다.
‘Foo.class’에 정의된 상수를 변경 및 컴파일 했을 때 'B.class’는 재컴파일하지 않고 ‘Foo.class’에서 변경한 상수에 대한 영향을 받아야 한다.

 

1. 들어 가며..

변하지 않는 값을 '상수(constant)'라고 합니다. 말 그대로 변할 수 없는 값입니다. 예를 들어 long type의 값인 100L이라는 상수를 선언하고자 한다면 통상 다음과 같이 선언 합니다.

final static public long = 100L;

그리고 통상적으로 상수들은 집합체인 상수 class에 모아둡니다. 이렇게 하는 이유는 크게 두가지 사유가 있습니다.

1. 여기 저기 흩어져 있을 경우 수정하려 하면 많은 class를 찾아서 수정해야 하므로 불편함.
2. 1번 같이 한 곳에 모아 두고 변경이 있을 경우 모아둔 class만 컴파일해도 참조하는 class를 재컴파일하지 않고 runtime시에 영향을 받기 위해.

그러나 위와 같이 ‘final static'으로 선언된 ‘primitive / String’ type은 생각처럼 작동하지 않습니다.

첨부된 ‘The Java Language Specification, Third Edition’에서 field에 대해서 부분적으로 많은 부분에서 설명하고 있습니다. 그 중에 다음과 같은 부분을 발췌했습니다. langspe-3.0.pdf / 348~349page ( Adobe reader 382~383 page)

The best way to avoid problems with 'inconstant constants' in widely-distributed code is to declare as compile time constants only values which truly are unlikely ever to change. Other than for true mathematical constants, we recommend that source code make very sparing use of class variables that are declared static and final. If the read-only nature of final is required, a better choice is to declare a private static variable and a suitable accessor method to get its value. Thus we recommend:
private static int N;
public static int getN() { return N; }
rather than:
public static final int N = ...;
There is no problem with:
public static int N = ...;
if N need not be read-only. We also recommend, as a general rule, that only truly constant values be declared in interfaces.We note, but do not recommend, that if a field of primitive type of an interface may change, its value may be expressed idiomatically as in:
interface Flags {
boolean debug = new Boolean(true).booleanValue();
}
insuring that this value is not a constant. Similar idioms exist for the other primitive types. One other thing to note is that static final fields that have constant values (whether of primitive or String type) must never appear to have the default initial value for their type (§4.12.5). This means that all such fields appear to be initialized first during class initialization (§8.3.2.1, §9.3.1, §12.4.2).


2. 현실

다음과 같이 Constants와 Bar가 있습니다. Bar는 Constants에 정의된 Foo를 참조합니다.



이때 Constants의 Foo를 변경하고 Constants만 컴파일 후에 실행하면 어떻게 될까요? 
다음은 ‘Foo =100L;’을 ‘Foo = 500L;’으로 변경한 결과 입니다.

예측으로는 value가 '525'가 나와야 합니다만 '125'가 나옵니다.


과연 어떻게 컴파일되었기에 그럴까요? 해서 디컴파일해서 내부를 보겠습니다.

우리가 원하는 결과는 'long foo = Constants.Foo + 25L;' 이라 생각 했지만, 'long l = 125L;'로  컴파일 되어 있네요.


3. 이유

‘primitive/String’ type에 final static 이 선언되면 컴파일시에 분석기가 상수로 판단해 위 처럼 참조로 컴파일하지 않고 정적으로 값을 넣어 주게 됩니다.

따라서 위와 같은 현상을 피하려면 final을 제거해 주면 되나, 애초에 상수라는 것은 runtime/컴파일시 어느 곳에서도 변경을 가할 수 없게 하기 위해서 final을 선언해 주기 때문에 근본적인 해결 책은 되지 못 합니다.

해서 가급적이면 primitive type을 사용하지 않고 object type을 사용해야 합니다.

final static public long Foo = 100L;

을 다음과 같이

final static public long Foo = new Long(100L).longValue();


4. 방안



위와 같이 변경하면 Constants만 변경하고 컴파일하면 원하는 결과를 얻게 됩니다.
주의 할 부분이 하나 있습니다. String type은 object type이 맞지만 다음과 같이 해야 합니다.

final static public String MSG = “메시지”;

를 다음과 같이

final static public String MSG = new String( “메시지" );

 

 

@

5 Comments
  • 프로필사진 Favicon of http://devyongsik.tistory.com 용식 2012.06.01 17:57 형님~!
    중간중간 코드가 보여야 할 부분 같은 곳이 비어있는 것은
    그냥 비워두신건가요? 요즘 티스토리 css 적용이 좀 이상하기도 하던데..

    코드 없어도 이해가 잘 되도록
    써 두시긴 하셨습니다만..^^

    잘 보았습니다!
  • 프로필사진 Favicon of https://b.pungjoo.com pungjoo.kim 2012.06.02 11:39 신고 api로 글을 올리고 에디터로 글을 수정 했더니 data가 꼬여서 이미지 관련한 html code가 이상해졌다..
    api로도 힘들고 내부 에디터로도 힘들고..글 좀 간만에 쓰려 했더니 역시 힘드네.. 남들은 어떻게 글을 그리 잘 쓰나.. 궁금하네..

    https://docs.google.com/document/d/1yBqARQ6zN9RTbb-Y7MN0a3MdY-Gr_EEjDFV6VkRIOB4/edit
  • 프로필사진 Favicon of http://devyongsik.tistory.com 용식 2012.06.18 19:45 지금은 잘 보이네요.. ^^
  • 프로필사진 kyu 2012.06.05 18:17 방안으로 final static 에서 final을 삭제해 버리면 안 될까요?
    위와 같은 현상으로 인해 고생을 한적이 있는데 저는 final을 지워버리는 방식으로 해결점을 찾았었습니다.
  • 프로필사진 Favicon of https://b.pungjoo.com pungjoo.kim 2012.06.06 17:45 신고 의견 감사합니다.
    그런데 본문에도 언급했습니다만, final을 삭제 하면 상수가 아니라 변수가 될 수도 있기 떄문입니다.
    final을 제거한 상태의 상수는 그냥 우리네 마음속에서 정의한 상수일 뿐이죠.

    >>따라서 위와 같은 현상을 피하려면 final을 제거해 주면 되나,
    >>애초에 상수라는 것은 runtime/컴파일시 어느 곳에 서도
    >>변경을 가할 수 없게 하기 위해서 final을 선언해 주기 때문에
    >>근본적인 해결책은 되지 못 합니다.

    정리하면..
    실행시나/컴파일시 어떤 경우도 변경되지 않음을 보장하는 것 까지 상수로 본다면 final을 삭제하면 안됩니다.

    @
댓글쓰기 폼