자바 정적 초기 화 블록 분석

8679 단어 자바static
자바 정적 초기 화 블록 분석
머리말
자바 응용 프로그램 을 개발 할 때 많은 장면 에서 정적 초기 화 블록 (Static Initialization Blocks) 을 사용 해 야 합 니 다.본 고 는 그것 에 대해 간략하게 분석 할 것 이다.
소개 하 다.
정적 초기 화 블록 은 static 키 워드 를 표시 하 는 괄호 에 닫 힌 일반 코드 블록 입 니 다.정적 초기 화 블록 은 클래스 가 초기 화 될 때 실 행 됩 니 다. 클래스 의 전체 수명 주기 에서 한 번 만 실 행 됩 니 다.따라서 클래스 의 정적 도 메 인 을 초기 화하 고 클래스 가 구 조 될 때 우선 실행 해 야 할 코드 를 실행 하 는 데 사 용 됩 니 다.
활용 단어 참조
JDK 소스 코드 중 몇 가지 유형 은 다음 과 같은 코드 를 사 용 했 습 니 다.
private static native void registerNatives();

static {
    registerNatives();
}

클래스 가 구 성 될 때 바로 registernatives 방법 으로 로 컬 함 수 를 등록 할 수 있 도록 정적 초기 화 블록 을 사용 합 니 다.
정적 초기 화 블록 은 상수 도구 클래스 에 도 사용 할 수 있 습 니 다. 설정 파일 에서 정적 속성 을 초기 화 할 수 있 습 니 다.
public class Constants {

    private static final String PFILE = "constants";
    private static String property = "";

    private Constants() {

    }

    static {
        copyProperties(PFILE);
    }

    private static void copyProperties(String fileName) {

        ResourceBundle rb = ResourceBundle.getBundle(fileName);
        Map<String, Object> map = new HashMap<String, Object>();
        Constants constants = new Constants();
        Enumeration<String> enums = rb.getKeys();

        while (enums.hasMoreElements()) {
            String key = enums.nextElement();
            map.put(key, rb.getString(key).trim());
        }

        try {
            BeanUtils.copyProperties(constants, map);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    public static String getProperty() {
        return property;
    }

    public void setProperty(String property) {
        Constants.property = property;
    }

}

실행 시기
정적 초기 화 블록 은 클래스 가 초기 화 될 때 실 행 됩 니 다. 구체 적 으로 다른 코드 블록 과 의 실행 순 서 는 무엇 입 니까?
예제 코드:
public class Demo {

    static {
        System.out.println("Static initialization block.");
    }

    {
        System.out.println("Initialization block.");
    }

    public Demo() {
        System.out.println("Constructor.");
    }

    public static void staticMethod() {
        System.out.println("Static method.");
    }

    public void dynamicMethod() {
        System.out.println("Dynamic method.");
    }

}
public class Main {

    public static void main(String args[]) throws ClassNotFoundException {
        System.out.println("Main method.");
        Class.forName("Demo");
        Class.forName("Demo");
    }

}

실행 결과:
Main method.
Static initialization block.

클래스. forName 방법 으로 클래스 를 불 러 올 때 클래스 가 초기 화 되 고 정적 초기 화 블록 이 실행 되 며 한 번 만 실 행 됩 니 다.
비 정적 방법
main 방법 수정:
public static void main(String args[]) {
    System.out.println("Main method.");
    new Demo().dynamicMethod();
}

실행 결과:
Main method.
Static initialization block.
Initialization block.
Constructor.
Dynamic method.

실행 순 서 는 정적 초기 화 블록 - > 초기 화 블록 - > 구조 방법 - > 인 스 턴 스 방법 입 니 다.
정적 방법
main 방법 수정:
public static void main(String args[]) {
    System.out.println("Main method.");
    Demo.staticMethod();
}

실행 결과:
Main method.
Static initialization block.
Static method.

정적 초기 화 블록 도 정적 방법 보다 우선 합 니 다.
main 방법
상기 main 방법 을 데모 류 에 복사 하여 실행 하면?
실행 결과:
Static initialization block.
Main method.
Static method.

정적 초기 화 블록 역시 정적 방법 보다 우선 하고 main 방법 보다 우선 합 니 다.
클래스 에서 main 방법 을 프로그램의 입구 로 정의 한 경우 클래스 가 직접 인용 되 기 때문에 클래스 의 초기 화 를 촉발 할 수 있 습 니 다.
Core Java 에서 언급 한 바 와 같이 main 방법 이 없 는 Hello, World 프로그램 을 만 들 수 있 습 니 다.
public class Hello {
    static {
        System.out.println("Hello, World!");
    }
}

자바 Hello 보기 결과 실행:
Hello, World!
Exception in thread "main" java.lang.NoSuchMethodError: main

System. exit (0) 를 추가 하여 이상 한 정 보 를 출력 하지 않도록 할 수 있 습 니 다.
그러나 이 프로그램 은 JDK 1.7 에서 직접 오 류 를 보고 합 니 다.
  :    Hello        ,         :
   public static void main(String[] args)

정적 필드
정적 초기 화 블록 과 정적 변수 간 의 실행 순 서 는 무엇 입 니까?
예제 코드:
public class Demo {

    static {
        x = 200;
    }

    public static int x = 100;

    public static void main(String args[]) {
        System.out.println("x = " + Demo.x);
    }

}

실행 결과:
x = 100

정적 변수 x 의 값 이 바 뀌 지 않 았 습 니 다. 그러면 정적 초기 화 블록 안의 코드 가 실행 되 었 습 니까?
정적 초기 화 블록 내 할당 문 앞 뒤 출력 x 의 값:
static {
    System.out.println("x1 = " + Demo.x);
    x = 2;
    System.out.println("x2 = " + Demo.x);
}

실행 결과:
x1 = 0
x2 = 200
x = 100

상기 코드 가 정적 초기 화 블록 에서 의 할당 문 구 는 변수 정의 에서 의 할당 문 구 를 먼저 실행 하 는 것 을 설명 합 니 다. 그런데 왜 이 정적 변 수 를 방문 할 수 있 습 니까?
인쇄 문 구 를 제거 한 후 어 셈 블 리 코드 보기:
Compiled from "Demo.java"
public class Demo {
  public static int x;

  static {};
    Code:
       0: sipush        200
       3: putstatic     #10                 // Field x:I
       6: bipush        100
       8: putstatic     #10                 // Field x:I
      11: return        

  public Demo();
    Code:
       0: aload_0       
       1: invokespecial #15                 // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]) throws java.lang.ClassNotFoundException;
    Code:
       0: return        
}

정적 변수의 정의 문 구 는 두 부분 으로 나 뉘 어 먼저 정 의 를 한 다음 에 값 을 부여 한 것 을 볼 수 있다.정적 변수 가 정 의 될 때 할당 작업 은 정적 초기 화 블록 의 할당 작업 뒤에 놓 여 있 습 니 다.
실제로 자바 c 컴 파일 을 사용 하여 바이트 코드 를 생 성 할 때 컴 파일 러 는 클래스 구조 기 < clinit > 방법 을 문법 트 리 에 추가 합 니 다. 클래스 초기 화 시 JVM 은 정적 영역 과 정적 초기 화 블록 의 논 리 를 모두 봉인 합 니 다.  방법 내.
코드 수정:
public class Demo {

    public static int x = 100;

    static {
        x = 200;
    }

    public static void main(String args[]) {
        System.out.println("x = " + Demo.x);
    }

}

실행 결과:
x = 200

따라서 헷 갈 리 지 않도록 정적 영역 에 값 을 부여 할 때 정적 방법 을 사용 하 는 것 이 좋 습 니 다.
public class Demo {

    public static int x = initX();

    public static int initX() {
        return 200;
    }

    public static void main(String args[]) {
        System.out.println("x = " + Demo.x);
    }

}

위 에서 언급 한 바 와 같이 정적 필드 와 정적 초기 화 블록 은 순서대로 실 행 됩 니 다. 그러면 다음 코드 의 실행 결 과 는 무엇 입 니까?
public class Demo {

    public static Demo demo = new Demo();

    static {
        System.out.println("Static initialization block.");
    }

    {
        System.out.println("Initialization block.");
    }

    public Demo() {
        System.out.println("Constructor.");
    }

    public static void main(String args[]) {
        System.out.println("Main method.");
    }

}

실행 결과:
Initialization block.
Constructor.
Static initialization block.
Main method.

이런 특수 한 상황 에서 정적 초기 화 블록 은 구조 방법 보다 늦게 실 행 될 수 있다.
상속 시
예제 코드:
public class SuperClass {

    static {
        System.out.println("Super static initialization block.");
    }

    public SuperClass() {
        System.out.println("Super constructor.");
    }

}
public class SubClass extends SuperClass {

    static {
        System.out.println("Sub static initialization block.");
    }

    public SubClass() {
        System.out.println("Sub constructor.");
    }

}
public class Main {

    public static void main(String[] args) {
        new SubClass();
    }

}

실행 결과:
Super static initialization block.
Sub static initialization block.
Super constructor.
Sub constructor.

이 예 에서 하위 클래스 의 대상 을 예화 하고 클래스 가 불 러 오 면 클래스 를 초기 화 합 니 다.실행 시 시스템 은 하위 클래스 를 초기 화 할 때 부모 클래스 를 초기 화 해 야 하기 때문에 부모 클래스 의 정적 초기 화 블록 을 먼저 실행 한 다음 에 하위 클래스 의 정적 초기 화 블록 을 실행 한 다음 에 하위 클래스 대상 을 실례 화 할 때 부모 클래스 대상 을 먼저 예화 해 야 하기 때문에 보통 부모 클래스 초기 화 블록 - > 하위 클래스 초기 화 블록 - > 부모 클래스 구조 방법 - > 하위 클래스 구조 방법 순 으로 합 니 다.더 복잡 한 상황 에 부 딪 히 면 구체 적 인 분석 이 필요 하 다.
총결산
간단하게 요약 하면 정적 초기 화 블록 은 클래스 가 초기 화 될 때 한 번 실 행 됩 니 다. 보통 이러한 종류의 모든 다른 방법 보다 우선 합 니 다. 정적 필드 간 의 실행 순서 와 원본 코드 작성 순서 가 같 습 니 다.하위 클래스 정적 초기 화 블록 을 실행 하기 전에 부모 클래스 정적 초기 화 블록 을 실행 합 니 다.기타 복잡 한 상황 의 구체 적 인 문 제 를 구체 적 으로 분석 하 다.

좋은 웹페이지 즐겨찾기