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


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.