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


87

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

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


2
당신이 언급하는 인용문을 포함하도록 질문을 편집 할 수 있습니다.
Oliver Charlesworth 2012 년

1
Java 언어 사양을 읽었습니까? 고의적으로 매우 읽기 쉬운 문서입니다. 그것을 읽었다면 무슨 일이 일어나고 있는지 이해할 것입니다. 그렇지 않다면, 당신은 ... 최소에서보다 구체적인 질문을 할 수 있습니다
마틴 Bodewes

이 Q & A는 stackoverflow.com/questions/3499214 의 중복이라고 생각합니다 .
Stephen C

답변:


72

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필드에 발생하지 않아야하는 클래스의 각 인스턴스화에서 실행되기 때문 입니다.


5
In case of static inner classes, they can not have static fields오타처럼 보입니다. 내부 클래스는 비 정적입니다.
Daniel Lubarov 2014

당신은 비록 대신 그러나 사용해야합니다
SURAJ 자이나교

JVM을 시작하고 처음으로 클래스를로드하면 (클래스가 어떤 방식 으로든 처음 참조 될 때 클래스 로더에 의해 수행됨) 정적 블록 또는 필드가 JVM으로 '로드'되고 액세스 가능하게됩니다.
nhoxbypass

1
불행히도이 답변에는 정적이 초기화되는시기에 대한 사실적으로 부정확 한 내용이 포함되어 있습니다. stackoverflow.com/a/3499322/139985를 참조하십시오 .
Stephen C

15

보다:

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

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


11

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


10

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

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

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


6

정적 변수

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

4

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

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
클래스는 초기화가 완료 될 때까지 초기화 된 것으로 표시되지 않습니다. 그렇지 않으면 의미가 없습니다. 초기화 됨으로 표시하는 것은 거의 마지막 단계입니다. JLS 12.4.2를 참조하십시오 .
Dave Newton

@DaveNewton : 무언가가 클래스를 참조하고 초기화를 시작하면 모든 추가 참조는 클래스를 초기화 된 것으로 취급합니다. 초기화를 시도하지 않고 초기화 될 때까지 기다리지 않습니다. 따라서 프로그램 시작에서 null이 아닌 것처럼 보이는 필드는 실제로 한동안 null 일 수 있습니다. 이것이 모든 혼란을 일으키는 원인을 이해하지 못합니다. 초기화되지 않은 클래스가 첫 번째 참조에서 초기화 된 것으로 "표시"되어 있다고 말하는 것이 가장 간단하다고 생각하며, 다른 모든 참조는이를 초기화 된 것으로 취급하므로 이것이 발생합니다.
RalphChapin

이전 주석에 대한 수정 : Dave Newton의 JLS 12.4.2에 설명 된대로 클래스가 초기화되는 동안 잠 깁니다 . 다른 스레드 클래스가 초기화 때까지 기다립니다. 그러나이 경우에는 영향을 미치지 않으며 모든 작업이 하나의 스레드에서 발생합니다.
RalphChapin

4

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

  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
        }
    }
    
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.