정적 클래스 초기화는 언제 발생합니까?


110

정적 필드는 언제 초기화됩니까? 클래스를 인스턴스화하지 않고 정적 필드에 액세스하는 경우 모든 정적 블록과 개인 정적 필드를 인스턴스화하는 데 사용되는 개인 정적 메서드가 그 순간에 (순서대로) 호출됩니까?

정적 메서드를 호출하면 어떻게됩니까? 또한 모든 정적 블록을 실행합니까? 방법 전에?


답변:


156

클래스의 정적 초기화는 일반적으로 다음 이벤트 중 하나가 처음 발생하기 직전에 발생합니다.

  • 클래스의 인스턴스가 생성되고
  • 클래스의 정적 메서드가 호출됩니다.
  • 클래스의 정적 필드가 할당됩니다.
  • 상수가 아닌 정적 필드가 사용되거나
  • 최상위 클래스의 경우 클래스 내에 어휘 적으로 중첩 된 assert 문이 실행됩니다 1 .

JLS 12.4.1을 참조하십시오 .

Class.forName(fqn, true, classLoader)또는 짧은 형식 을 사용하여 클래스를 강제로 초기화 할 수도 있습니다 (아직 초기화되지 않은 경우).Class.forName(fqn)


1-마지막 글 머리 기호는 Java 6에서 Java 8까지의 JLS에 있었지만 분명히 사양에있는 실수였습니다. Java 9 JLS에서 마침내 수정되었습니다 . 소스 참조 .


9
하지만 일반적인 함정이 있습니다. 프리미티브 및는 String대체되며 참조되지 않습니다. class Other { public static final int VAL = 10; }일부 클래스에서 를 참조 MyClass { private int = Other.VAL; }하면 클래스 Other가로드되지 않습니다. 대신 컴파일러는 컴파일 타임에 최종 필드를 간단히 대체합니다.
Rafael Winterhalter 2013 년

6
@RafaelWinterhalter-예 ... 그것은 상수 정적 필드 케이스입니다.
Stephen C

2
@RafaelWinterhalter, 이것은 모든 '정적 최종'프리미티브 또는 String변수에 해당 되지 않으며 상수 표현식으로 초기화 된 변수 만 있습니다.
Lew Bloch

1
예, 필드 static는 일반적인 경우 일 필요조차 없습니다 .
Rafael Winterhalter

1
동일한 프로그래밍 언어입니다. 예.
Stephen C

14

정적 필드는 정적 이니셜 라이저 및 정적 필드의 초기화를 포함하는 클래스 로딩 (로드, 링크 및 초기화) 의 초기화 "단계" 중에 초기화 됩니다. 정적 이니셜 라이저는 클래스에 정의 된 텍스트 순서로 실행됩니다.

예를 고려하십시오.

public class Test {

   static String sayHello()  {
      return a;
   }

   static String b = sayHello(); // a static method is called to assign value to b.
                                 // but its a has not been initialized yet.

   static String a = "hello";

   static String c = sayHello(); // assignes "hello" to variable c

    public static void main(String[] arg) throws Throwable {
         System.out.println(Test.b); // prints null
         System.out.println(Test.sayHello()); // prints "hello"
    }
}

정적 범위에서를 호출 null했을 때 sayHello정적 변수 a가 초기화되지 않았기 때문에 Test.b가 인쇄 됩니다 .


6
엄밀히 말하면 초기화는 클래스 로딩의 "단계"가 아닙니다. 실제로 일부 클래스 로드 수 있지만 응용 프로그램에서 실제로 사용하지 않는 경우 초기화되지 않습니다.
Stephen C

@Stephen C 당신이 맞아요, 더 나은 용어가 부족해서 그것을 사용했습니다. 아마도 그것을 인용하겠습니다.
naikus

@StephenC는 클래스 로딩이 발생하는 동안 정적 변수 (& 메서드)에 메모리를 할당하지만 해당 정적 변수는 코드에서 제공된 값으로 초기화되지 않는다는 의미입니까? b-> sayHello ()-> a, 'a'가 메모리에 있지만 값이 아직 할당되지 않은 것처럼 보였기 때문입니다.
Shabbir Essaji

기본적으로 그렇습니다.
Stephen C

1

예, 모든 정적 이니셜 라이저는 클래스에 처음 액세스하기 전에 실행됩니다. 다른 방법이라면 버그라고 부를 것입니다.


클래스를 초기화하지 않고 참조하는 방법이 있습니다.
Lew Bloch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.