[java] 정적 초기화 블록

내가 이해하는 한 “정적 초기화 블록”은 한 줄에서 수행 할 수없는 경우 정적 필드의 값을 설정하는 데 사용됩니다.

그러나 왜 우리에게 특별한 블록이 필요한지 이해하지 못합니다. 예를 들어 필드를 정적으로 (값을 할당하지 않고) 선언합니다. 그런 다음 위의 선언 된 정적 필드에 값을 생성하고 할당하는 몇 줄의 코드를 작성하십시오.

왜이 라인이 다음과 같은 특수 블록에 필요 static {...}합니까?



답변

비 정적 블록 :

{
    // Do Something...
}

클래스의 인스턴스가 생성 될 때마다 호출 됩니다 . 정적 블록 에만 호출됩니다 한 번 클래스 자체가 초기화 될 때 해당 유형의 많은 개체를 생성하는 방법에 상관없이,.

예:

public class Test {

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

    {
        System.out.println("Non-static block");
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = new Test();
    }
}

인쇄합니다 :

Static
Non-static block
Non-static block


답변

정적 초기화 블록에 없다면 어디에 있었습니까? 초기화 목적으로 만 로컬 변수를 선언하고 필드와 구별하는 방법은 무엇입니까? 예를 들어, 어떻게 작성하고 싶 습니까 ?

public class Foo {
    private static final int widgets;

    static {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        widgets = first + second;
    }
}

경우 firstsecond블록에없는, 그들은 필드처럼 보일 것입니다. 블록 static이 앞에 없는 블록에 있으면 정적 초기화 블록 대신 인스턴스 초기화 블록으로 계산되므로 생성 된 인스턴스 총 한 번이 아니라 한 번 실행 됩니다.

이제이 특별한 경우에 대신 정적 메소드를 사용할 수 있습니다.

public class Foo {
    private static final int widgets = getWidgets();

    static int getWidgets() {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        return first + second;
    }
}

…하지만 동일한 블록 내에 여러 변수를 할당하거나 아무것도하지 않을 때는 작동하지 않습니다 (예 : 무언가를 로깅하거나 원시 라이브러리를 초기화하려는 경우).


답변

예를 들면 다음과 같습니다.

  private static final HashMap<String, String> MAP = new HashMap<String, String>();
  static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

“정적”섹션의 코드는 클래스의 인스턴스가 생성되기 전에 (그리고 정적 메소드가 다른 곳에서 호출되기 전에) 클래스로드시 실행됩니다. 이렇게하면 클래스 리소스를 모두 사용할 수 있습니다.

정적이 아닌 초기화 블록을 가질 수도 있습니다. 그것들은 클래스에 대해 정의 된 생성자 메소드 세트의 확장처럼 작동합니다. 키워드 “static”이 꺼져 있다는 점을 제외하면 정적 초기화 블록과 같습니다.


답변

런타임 중에 클래스를 한 번만 로드하는 것과 같이 실제로 값을 지정하지 않으려는 경우에도 유용 합니다.

예 :

static {
    try {
        Class.forName("com.example.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
    }
}

또 다른 이점이 있습니다. 예외를 처리하는 데 사용할 수 있습니다. 그 상상 getStuff()여기에서 발생 Exception하는 정말 catch 블록에 속하는 :

private static Object stuff = getStuff(); // Won't compile: unhandled exception.

다음 static초기화 여기에 유용합니다. 거기에서 예외를 처리 할 수 ​​있습니다.

또 다른 예는 할당하는 동안 수행 할 수없는 작업을 나중에 수행하는 것입니다.

private static Properties config = new Properties();

static {
    try {
        config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
    } catch (IOException e) {
        throw new ExceptionInInitializerError("Cannot load properties file.", e);
    }
}

JDBC 드라이버 예제로 돌아가려면 괜찮은 JDBC 드라이버 자체도 static초기화 프로그램을 사용하여에 자신을 등록합니다 DriverManager. 또한 볼 대답을.


답변

나는 static block단지 구문 설탕 이라고 말할 것 입니다. static블록으로 할 수있는 것은없고 다른 것으로는 할 수 없습니다.

여기에 게시 된 일부 예제를 재사용하십시오.

이 코드는 static이니셜 라이저 를 사용하지 않고 다시 작성할 수 있습니다 .

방법 # 1 : 포함 static

private static final HashMap<String, String> MAP;
static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

방법 # 2 : 미포함 static

private static final HashMap<String, String> MAP = getMap();
private static HashMap<String, String> getMap()
{
    HashMap<String, String> ret = new HashMap<>();
    ret.put("banana", "honey");
    ret.put("peanut butter", "jelly");
    ret.put("rice", "beans");
    return ret;
}


답변

존재해야하는 몇 가지 실제 이유가 있습니다.

  1. 초기화 static final 에서 예외가 발생할 수있는 멤버 초기화
  2. 초기화 static final계산 된 값으로 멤버

사람들은 static {}특정 클래스 (예 : JDBC 드라이버)를로드하는 것과 같이 런타임 내에서 클래스가 의존하는 것을 초기화하는 편리한 방법으로 블록 을 사용하는 경향이 있습니다 . 다른 방법으로도 가능합니다. 그러나 위에서 언급 한 두 가지는 static {}블록 과 같은 구조로만 수행 할 수 있습니다 .


답변

객체가 정적 블록으로 구성되기 전에 클래스에 대해 한 번의 코드 비트를 실행할 수 있습니다.

예 :

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}