2017-02-28 9 views
1

다음 코드에서 readSide()SIDE을 나타내며 다른 정적 변수를 초기화하기 위해 호출 할 때 SIDE의 선언에 할당 된 값이 아닌 0의 값을 갖는 것으로 나타납니다.Java가 컴파일러 또는 런타임 오류없이 초기화되지 않은 최종 정적 변수를 읽는시기와 이유는 무엇입니까?

import java.util.Random; 

public class StaticTest { 

    private final static float SIDE_FROM_METHOD = readSide(); 
    private final static float SIDE = 100.0f * new Random().nextFloat(); 

    private static float readSide() { 
     System.out.println("In readSide(): SIDE=" + SIDE); 

     return SIDE; 
    } 

    public static void main(String[] args) { 
     System.out.println("In main(): SIDE_FROM_METHOD=" + SIDE_FROM_METHOD); 
     System.out.println("In main(): SIDE=" + SIDE); 
     System.out.println("In main(): readSide() return=" + readSide()); 
    } 
} 

샘플 출력 : SIDE 따라서 비록

In readSide(): SIDE=0.0 
In main(): SIDE_FROM_METHOD=0.0 
In main(): SIDE=85.84305 
In readSide(): SIDE=85.84305 
In main(): readSide() return=85.84305 

는 일정한 것으로 가정하고, 자바는 이루어되는 예외를 발생하거나 초기화 순서를 보장하거나보다 런타임에 값을 변경할 수 있도록 의존성 순서.

"최종 정적"개체를 정의하는 순서가 문제가되는 동작의 원인이라고 생각합니다.하지만 그 대신에 예외가 발생하지 않는 이유는 무엇입니까?

SIDE 경우 오히려 계산 된 값보다 리터럴로 초기화된다

private final static float SIDE=100.0f; 

...이 후 출력 걸쳐 100.0이다.

In readSide(): SIDE=100.0 
In main(): SIDE_FROM_METHOD=100.0 
In main(): SIDE=100.0 
In readSide(): SIDE=100.0 
In main(): readSide() return=100.0 

왜 이것이 다른가요?

+5

이상한 행동이 의미하는 것을 포함시킬 수 있습니까? – corriganjc

+0

왜 오류가 있습니까? –

+0

@corriganjc 샘플 출력이 질문에 추가되었습니다. – user2999069

답변

2

상수의 정의에 따라 약간의 미묘한 동작이 발생했습니다.

우리는 대부분 final static 변수가 "상수"라고 가정하며 이는 프로그래밍에 익숙해지기에 충분합니다.

그러나 Java Language Specification states in section 4.12.4 :

(강조 광산)

원시 형 또는 문자열 유형의 변수, 즉, 컴파일 시간 초기화 최종 와 상수 식 (§15.28) , 상수 변수는 입니다. 변수는 상수 또는 변수 클래스 초기화 (§12.4.1) 이진 호환성 (§13.1, §13.4.9) 및 명확한 지정 (§16)에 대해 영향을 가질 수 없다 여부

.

... "컴파일 타임 상수 표현"이 무슨 뜻인지 알아 보려면 다른 섹션으로 이동해야합니다.간단히 말해서, 100.0f은 컴파일 타임 상수 표현식입니다. 따라서 100.0f * 10입니다. 100.0f * new Random().nextFloat()은 컴파일 타임에 계산할 수 없기 때문에 아닙니다.

첫 번째 예에서는 SIDE이 엄격하게 상수가 아니므로 초기화가 다른 순서로 발생합니다. 자세한 내용은 JLS 12.4.1입니다.

SIDE = 100f으로 프로그램을 변경하면 컴파일 타임 상수가되며 따라서 규칙이 변경되고 컴파일 타임에 할당됩니다.

알고 계시면 이러한 문제를 해결하는 것이 쉽습니다. 보시다시피, 과제를 올바른 순서로 정리하면 증상이 수정됩니다.

+0

옳은 대답을 얻은 것 같지만 생성자에 넣는 것에 대한 아이디어는 (최종 정적) 코드 샘플이 반드시 작동하지 않을 것이라는 점에서 패배합니다. 내가 생각할 수있는 유일한 수정 사항은 주문이 올바른지 확인하거나이 부분을 정적 코드 블록에 작성하는 것입니다. – user2999069

+0

@ user2999069 당신 말이 맞아요, 생성자에 관한 것은 뇌간이었고 저는 그것을 제거했습니다. – slim

1

이상한 동작은 private final static float[] POINTS = generatePoints();SIDE 상수를 초기화하지 않은 경우에 발생합니다. 문제를 해결하려면 해당 줄을 SIDE의 초기화 아래로 이동하십시오. 모든 잘못 때문에 SIDE는 초기화하기 전에 값 0.0을 유지하기 때문에 예외가없는

이유는 generatePoints의 계산 0로 그 값을 읽입니다.

각 유형에 대해 사용되는 값은 JLS 4.12.5을 참조하십시오.

+0

나는 그것을 이해하지만 SIDE 값은 정의되지 않았거나 정의되어 있어야하고 상수이기 때문에 값이 전혀 없어야하고 이것이 원인이된다. 오류 또는 올바른 값으로 정의되었지만 상수는 코드 실행 중 값을 변경합니다! (이것은 예기치 않은 동작의 정의입니다.) – user2999069

+0

@ user2999069 - 완벽한 세상에서 그렇습니다. 참조를 추가했습니다. – OldCurmudgeon

+0

저는 변수의 초기 값을 이해합니다. 그러나 이것은 상수 (최종 정적 플로트)이므로 값을 변경해서는 안된다고 생각했습니다. 이클립스 IDE를 사용하고 있었고 기능 소스를 사용했습니다> 메서드와 멤버를 사전 순으로 정렬하는 멤버를 정렬합니다. 이렇게하면 어디에서 발생 했나요? (실행 순서 때문이라는 것을 알았지 만, 이것은 일어날 것입니다.) – user2999069