[java] 정적 변수는 언제 초기화됩니까?

정적 변수가 기본값으로 초기화되는시기가 궁금합니다. 클래스가로드 될 때 정적 변수가 생성 (할당) 된 다음 선언의 정적 이니셜 라이저 및 초기화가 실행되는 것이 맞습니까? 어떤 시점에서 기본값이 제공됩니까? 이것은 순방향 참조의 문제로 이어집니다.

또한 정적 필드가 시간 내에 초기화되지 않는 이유에 대한 질문을 참조하여 이것을 설명 할 수 있다면 제발 부탁드립니다 . 특히 같은 사이트에서 Kevin Brock이 제공 한 답변입니다. 세 번째 포인트를 이해할 수 없습니다.



답변

Java 정적 변수 메소드 참조 에서 :

  • 객체 (인스턴스)가 아닌 클래스에 속하는 변수입니다.
  • 정적 변수는 실행 시작시 한 번만 초기화됩니다. 이러한 변수는 인스턴스 변수를 초기화하기 전에 먼저 초기화됩니다.
  • 클래스의 모든 인스턴스에서 공유 할 단일 복사본
  • 정적 변수는 클래스 이름으로 직접 액세스 할 수 있으며 개체가 필요하지 않습니다.

인스턴스 및 클래스 (정적) 변수는 의도적으로 초기화하지 못하면 자동으로 표준 기본값으로 초기화됩니다. 지역 변수가 자동으로 초기화되지는 않지만 사용하기 전에 지역 변수를 초기화하거나 해당 지역 변수에 값을 할당하지 못하는 프로그램을 컴파일 할 수 없습니다.

컴파일러가 실제로하는 일은 모든 정적 변수 이니셜 라이저와 모든 정적 이니셜 라이저 코드 블록을 클래스 선언에 나타나는 순서대로 결합하는 단일 클래스 초기화 루틴을 내부적으로 생성하는 것입니다. 이 단일 초기화 절차는 클래스가 처음로드 될 때 한 번만 자동으로 실행됩니다.

내부 클래스의 경우 정적 필드를 가질 수 없습니다.

내부 클래스는 명시 적 또는 암시 적으로 선언되지 않은 중첩 된 클래스입니다 static.

내부 클래스는 정적 이니셜 라이저 (§8.7) 또는 멤버 인터페이스를 선언 할 수 없습니다.

내부 클래스는 상수 변수가 아닌 경우 정적 멤버를 선언 할 수 없습니다.

JLS 8.1.3 내부 클래스 및 엔 클로징 인스턴스 참조

finalJava의 필드는 선언 위치와 별도로 초기화 할 수 있지만 필드에는 적용 할 수 없습니다 static final. 아래 예를 참조하십시오.

final class Demo
{
    private final int x;
    private static final int z;  //must be initialized here.

    static
    {
        z = 10;  //It can be initialized here.
    }

    public Demo(int x)
    {
        this.x=x;  //This is possible.
        //z=15; compiler-error - can not assign a value to a final variable z
    }
}

하나 개가 있기 때문이다 사본static대신 인스턴스 변수와 우리가 초기화하려고하면 같은 유형의 각 인스턴스와 관련된보다, 유형과 관련된 변수 z유형 static final, 그것은 다시 초기화하려고 시도 생성자 내에서 static final유형 필드를 z생성자는 정적 final필드에 발생하지 않아야하는 클래스의 각 인스턴스화에서 실행되기 때문 입니다.


답변

보다:

특히 마지막은 정적 변수가 초기화되는시기와 순서설명 하는 자세한 초기화 단계 를 제공합니다 ( final컴파일 시간 상수 인 클래스 변수 및 인터페이스 필드가 먼저 초기화된다는 점에 유의하세요).

포인트 3에 대한 구체적인 질문이 무엇인지 모르겠습니다 (중첩 된 것을 의미한다고 가정할까요?). 자세한 시퀀스는 이것이 재귀 적 초기화 요청이므로 초기화를 계속할 것이라고 설명합니다.


답변

정적 필드는 클래스 로더가 클래스를로드 할 때 초기화됩니다. 이때 기본값이 지정됩니다. 이것은 소스 코드에 나타나는 순서대로 수행됩니다.


답변

초기화 순서는 다음과 같습니다.

  1. 정적 초기화 블록
  2. 인스턴스 초기화 블록
  3. 생성자

프로세스에 대한 자세한 내용은 JVM 사양 문서에 설명되어 있습니다.


답변

정적 변수

  • 객체 (인스턴스)가 아닌 클래스에 속하는 변수입니다.
  • 정적 변수는 실행 시작시 (Classloader가 처음으로 클래스를로드 할 때) 한 번만 초기화됩니다.
  • 이러한 변수는 인스턴스 변수를 초기화하기 전에 먼저 초기화됩니다.
  • 클래스의 모든 인스턴스에서 공유 할 단일 복사본
  • 정적 변수는 클래스 이름으로 직접 액세스 할 수 있으며 객체가 필요하지 않습니다.


답변

다른 질문의 코드로 시작합니다.

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

이 클래스에 대한 참조는 초기화를 시작합니다. 먼저 클래스가 초기화 됨으로 표시됩니다. 그런 다음 첫 번째 정적 필드가 MyClass ()의 새 인스턴스로 초기화됩니다. myClass는 즉시 MyClass 인스턴스에 대한 참조를 제공 합니다. 공간이 있지만 모든 값은 null입니다. 이제 생성자가 실행되고obj null 인을 .

이제 클래스 초기화로 돌아가서 : obj새로운 실제 객체에 대한 참조가 만들어지면 완료됩니다.

이것이 다음과 같은 명령문에 의해 설정된 경우 : MyClass mc = new MyClass();새 MyClass 인스턴스를위한 공간이 다시 할당되고 참조가에 배치됩니다 mc. 생성자가 다시 실행되고 다시 인쇄 obj되며 이제는 null이 아닙니다.

여기서 진짜 트릭은를 사용할 때에서 new와 같이 WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weii즉시 nulled 메모리에 대한 참조가 제공된다는 것입니다. 그러면 JVM은 계속해서 값을 초기화하고 생성자를 실행합니다. 그러나 다른 스레드에서 참조하거나 예를 들어 클래스 초기화에서 참조하여 참조 weii 하기 전에 참조하는 경우 null 값으로 채워진 클래스 인스턴스가 표시됩니다.


답변

정적 변수는 다음 세 가지 방법으로 초기화 할 수 있습니다.

  1. 선언 할 때 초기화 할 수 있습니다.
  2. 또는 정적 블록을 만들어 수행 할 수 있습니다.

    static {
            // whatever code is needed for initialization goes here
        }
    
  3. 정적 블록에 대한 대안이 있습니다. 개인 정적 메서드를 작성할 수 있습니다.

    class name {
        public static varType myVar = initializeVar();
    
        private static varType initializeVar() {
            // initialization code goes here
        }
    }