2012-03-14 2 views
2

모든 코드에서 오류가 발견되었지만 모든 상황에서 머리를 뒤집어 쓰는 것처럼 보이지는 않습니다. 나는 나보다 똑똑한 사람이 "네, 오류입니다"라고 말할 수 있고, 더 나아가 내 구현에 대한 또 다른 대안을 제안하기를 바랄 수 있습니다.서로 참조하는 정적 필드를 초기화하는 중 오류가 발생했습니다.

오류의 원인은 두 클래스의 정적 필드가 초기화되는 방식이라고 생각합니다. (FooClass에있는) 하나는 다른 필드를 참조하여 초기화되고 에있는 하나는 Foo 유형의 객체를 생성하여 초기화됩니다. 미안 해요. 설명은 결코 내 강점이 아니었다.

저는 문제를 줄이기 위해 더 많은 시간을 보냈습니다. 그리고 문제를 보여줄 수있는 무언가를 가지고 있습니다.

public class Tester { 

    static class FooClass { 
     static final FooClass ITS_FOO = MyUtility.MY_FOO; 
    } 

    static class MyUtility { 
     static final FooClass MY_FOO = new FooClass(); 

     static FooClass create() { 
      return new FooClass(); 
     } 
    } 

    public static void main(String[] args) { 
     System.out.println("utility's: " + MyUtility.create()); // Line "A" 
     System.out.println("class's: " + FooClass.ITS_FOO); // Line "B" 
    } 
} 

내가이 디자인이 이상하게 보이는 실현,하지만 훨씬 그것을 정당화하려고하지 않을 것이다 (실제 코드가 구성되어있다 "이상한"도하지만 등 다른 가시성 별도의 클래스 내에서). 이렇게하는 더 좋은 방법에 대한 제안을 해주시면 감사하겠습니다.

적어도이 프로그램과 관련된 문제의 요지는 FooClass.ITS_FOO 필드가 라인 B가 실행될 때 null이라는 것입니다. 라인 A와 B의 순서를 바꾸면, 어느 필드도 null이 아닙니다.

In what order do static initializer blocks in Java run?과 같은 질문을 보았습니다. 그러나 이러한 유형의 상호 참조 초기화가 수행되는 방법을 설명하는 메시지는 Java Language Spec입니다.

불행하게도이 샘플은 우리의 실제 구현에서 지금까지 제거 되었기 때문에 모든 솔루션을 다시 번역하는 데 동일한 시간이 소요될 것입니다.하지만 설명을 듣는 것이 좋습니다.

답변

4

예, 먼저 FooClass을 강제로 초기화하면 MyUtility이 초기화됩니다. MY_FOO의 초기화 프로그램은 FooClass이 이미이 스레드에서 초기화 중이므로이므로 MY_FOO은 null이 아닙니다.

한편

, 당신은 (현재 단지 채무 불이행)를 FooClass 생성자에서 ITS_FOO을 관찰, 당신은이 동작 잘 스펙에 설명입니다

... 거기 널 (null)입니다 볼 수 있습니다 - 섹션을 당신은 모든 세부 사항을 제공하기 위해 링크했습니다 -하지만 기본적으로 은 정적 이니셜 라이저가 서로를 참조하는 두 가지 유형이 있습니다. 미묘한 방법으로 문제를 해결하려고하지 마십시오. 종속성을 제거하십시오. 이것이 고통 스러울 수도 있다는 것을 알지만, 실제로 다른 모든 문제를 생각해 볼 가치는 없습니다. 해결 행하는

한가지 방법은 다른 종류의 모두에 의존 할 수있는 임의의 정적 다른 유형에 의존하지 않는 초기화와 함께 세 번째 유형을 추출 할 수있다. 정적 초기화 적게하고 물론

도 도움이 :)입니다

+0

불행하게도 (세 번째 유형 수정 WRT), 디자인의 기본적인 부분은 FooClass.ITS_FOO' 필드의 특별한 종류 인'이다 'FooClass'. 내 예를 단순화하면 그 사실을 없앨 수 있습니다. (.하지만 클래스가 초기화되기 전에 생성자가 실행될 수 있다는 것은 여전히 ​​놀랍습니다. (이 경우에는 작동하도록 만드는 일종의 마술처럼 들리지만). 어쨌든, 나는 의존성 중 하나를 제거하는 방법을 생각할 것이다. 이제는 나쁜 생각처럼 들립니다 ... –

+0

@Rob : 12.4.2 절에서이 지점에서 다룹니다. "C의 Class 객체가 현재 스레드에서 C에 대한 초기화가 진행 중임을 나타내면이 속성은 다음과 같아야합니다. 재귀 적 초기화 요청 .LC를 해제하고 정상적으로 완료하십시오. " –

+0

아! 나는 이전에이 말을 전적으로 따르지 않았지만, 이제는이 사건과 "완전한 정상"이 오해의 소지가 있다는 것을 알았습니다 ... "정말로 나쁜 생각"으로 이어졌습니다. 감사! –

관련 문제