programing

스태틱 초기화 블록

kingscode 2022. 7. 15. 22:12
반응형

스태틱 초기화 블록

제가 알기론 "static initialization block"은 한 줄로 할 수 없는 경우 정적 필드의 값을 설정하는 데 사용됩니다.

하지만 나는 왜 우리가 그것을 위해 특별한 블록이 필요한지 이해할 수 없다.예를 들어 필드를 스태틱(값 할당 없음)으로 선언합니다.그런 다음 위에 선언된 정적 필드에 값을 생성하고 할당하는 코드의 여러 줄을 작성합니다.

은 왜 '하다'와 같은 합니까?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;
    }
}

iffirst ★★★★★★★★★★★★★★★★★」second블록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 키워드가 생략된 것을 제외하면 스태틱 이니셜라이저 블록과 똑같이 보입니다.

런타임 중에 일부 클래스를 한 만 로드하는 것과 같이 실제로 값을 할당하지 않을 때도 유용합니다.

예.

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

저기, 또 다른 장점이 있어요. ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★♪해 보세요.getStuff()서 여 an an an 를 던지다Exception캐치블록에 속합니다.

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

a then then then thenstatic여기서 합니다.initializer는 initializer입니다.을 사용법

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

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하여 initializer에 합니다.DriverManager이것과 이 답을 보세요.

라고 말할 수 것 같다.static block당신이 할 수 일은 .static차단하고 다른 어떤 것도 하지 않습니다.

여기에 게재된 예시를 재사용하기 위해.

은 이 코드를 사용하지 않고 할 수 .static이니셜라이저

법:1: 포 methodstatic

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

법2: 포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());
  }
}

스태틱 블록이 스태틱필드에만 액세스 할 수 있다고 생각하는 것은 일반적인 오해입니다.이를 위해 실제 프로젝트에서 자주 사용하는 코드(약간 다른 문맥의 다른 답변에서 부분적으로 복사)를 아래에 나타냅니다.

public enum Language { 
  ENGLISH("eng", "en", "en_GB", "en_US"),   
  GERMAN("de", "ge"),   
  CROATIAN("hr", "cro"),   
  RUSSIAN("ru"),
  BELGIAN("be",";-)");

  static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>(); 
  static { 
    for (Language l:Language.values()) { 
      // ignoring the case by normalizing to uppercase
      ALIAS_MAP.put(l.name().toUpperCase(),l); 
      for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l); 
    } 
  } 

  static public boolean has(String value) { 
    // ignoring the case by normalizing to uppercase
    return ALIAS_MAP.containsKey(value.toUpper()); 
  } 

  static public Language fromString(String value) { 
    if (value == null) throw new NullPointerException("alias null"); 
    Language l = ALIAS_MAP.get(value); 
    if (l == null) throw new IllegalArgumentException("Not an alias: "+value); 
    return l; 
  } 

  private List<String> aliases; 
  private Language(String... aliases) { 
    this.aliases = Arrays.asList(aliases); 
  } 
} 

Initializer)를 유지하기 위해 됩니다.ALIAS_MAP에일리어스 세트를 원래 열거형으로 매핑합니다.은, 「으로서 「Built-in value Of」라고 하는 값 Of 에 되는 것을 으로 하고 .Enum그 자체입니다.

와 같이 """ 합니다.private 들 fieldaliases중요한 것은, 이 점에 주의해 주세요.static에 이미 할수 있습니다.Enum(예: ( value ( ( (:ENGLISH이는 타입의 경우 초기화 실행순서가 다음과 같이 되어 있기 때문입니다.static private보다 앞의 되었습니다.static블록이 호출되었습니다.

  1. Enum암시적 정적 필드인 상수입니다.이렇게 하려면 Enum 생성자 및 인스턴스 블록과 인스턴스 초기화도 먼저 수행해야 합니다.
  2. static발생 순서대로 정적 필드를 차단하고 초기화합니다.

가 어긋난 전)static블록)은 주의할 필요가 있습니다., 싱글톤과, 합니다.

public class Foo {
  static { System.out.println("Static Block 1"); }
  public static final Foo FOO = new Foo();
  static { System.out.println("Static Block 2"); }
  public Foo() { System.out.println("Constructor"); }
  static public void main(String p[]) {
    System.out.println("In Main");
    new Foo();
  }
}

이 출력은 다음과 같습니다.

Static Block 1
Constructor
Static Block 2
In Main
Constructor

스태틱 초기화는 컨스트럭터 앞이나 다음 이후에도 실제로 발생할 수 있습니다.

메인 메서드에서 Foo에 액세스하는 것만으로 클래스가 로드되고 정적 초기화가 시작됩니다.그러나 Static 초기화의 일부로서 다시 static 필드의 컨스트럭터를 호출하고 그 후 static 초기화를 재개하여 메인 메서드 내에서 호출된 컨스트럭터를 완료합니다.나는 우리가 정상적인 코딩에서는 다루지 않아도 되는 다소 복잡한 상황입니다.

이에 대한 자세한 내용은 "유효한 Java" 을 참조하십시오.

정적 필드(클래스의 인스턴스가 아닌 클래스에 속하기 때문에 "class variable"이라고도 합니다.즉, 어떤 오브젝트에도 속하지 않고 클래스에 관련지어져 있기 때문에 "class variable"이라고도 불립니다)가 있어 초기화할 필요가 있습니다.따라서 이 클래스의 인스턴스를 만들지 않고 이 스태틱필드를 조작하는 경우는, 다음의 3개의 방법으로 실행할 수 있습니다.

1- 변수를 선언할 때 초기화하기만 하면 됩니다.

static int x = 3;

2- 정적 초기화 블록:

static int x;

static {
 x=3;
}

3- 클래스 변수에 액세스하여 초기화하는 클래스 메서드(static 메서드)가 있습니다.이것은 위의 스태틱블록의 대체 수단입니다.프라이빗 스태틱 메서드를 쓸 수 있습니다.

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

정적 방법 대신 정적 초기화 블록을 사용하는 이유는 무엇입니까?

그것은 당신의 프로그램에 필요한 것에 달려있다.그러나 정적 초기화 블록은 한 번 호출되며 클래스 메서드의 유일한 장점은 클래스 변수를 다시 초기화할 필요가 있는 경우 나중에 재사용할 수 있다는 것입니다.

프로그램에 복잡한 어레이가 있다고 가정해 보겠습니다.예를 들어 루프에 사용)를 초기화하면 이 배열의 값이 프로그램 전체에서 변경되지만 어느 시점에서 다시 초기화(초기값으로 돌아가기)해야 합니다.이 경우 프라이빗 스태틱메서드를 호출할 수 있습니다.프로그램에서 값을 다시 초기화할 필요가 없는 경우 정적 블록만 사용할 수 있으며 나중에 프로그램에서 사용하지 않을 것이기 때문에 정적 메서드는 필요하지 않습니다.

주의: 정적 블록은 코드에 표시되는 순서대로 호출됩니다.

예 1:

class A{
 public static int a =f();

// this is a static method
 private static int f(){
  return 3;
 }

// this is a static block
 static {
  a=5;
 }

 public static void main(String args[]) {
// As I mentioned, you do not need to create an instance of the class to use the class variable
  System.out.print(A.a); // this will print 5
 }

}

예 2:

class A{
 static {
  a=5;
 }
 public static int a =f();

 private static int f(){
  return 3;
 }

 public static void main(String args[]) {
  System.out.print(A.a); // this will print 3
 }

}

가 있는 는, 「」를 .static {...}이치노

예를 들어 스태틱멤버를 컨피규레이션파일 또는 데이터베이스에 저장되어 있는 값으로 설정해야 하는 경우.

, 스태틱에 합니다.Map초기 멤버 선언에 이러한 값을 추가할 수 없습니다.

보충으로서 @Pointy가 말한 것처럼

"static" 섹션의 코드는 클래스의 인스턴스가 생성되기 전(및 다른 곳에서 스태틱메서드가 호출되기 전) 클래스 로드 시 실행됩니다.

해서 '더하다'를 넣게 .System.loadLibrary("I_am_native_library")이치노

static{
    System.loadLibrary("I_am_a_library");
}

관련 라이브러리가 메모리에 로드되기 전에 네이티브 메서드가 호출되지 않음을 보증합니다.

oracle의 loadLibrary에 따르면:

이 메서드가 같은 라이브러리 이름으로 여러 번 호출될 경우 두 번째 콜과 후속 콜은 무시됩니다.

따라서 System.loadLibrary를 넣는 것은 라이브러리가 여러 번 로드되는 것을 피하기 위해 사용되지 않습니다.

클래스 가 '어플리케이션 클래스'로 .java.class.Class실행될 입니다.이때 정적 블록이 실행됩니다.을 사용하다

public class Main {

    private static int myInt;

    static {
        myInt = 1;
        System.out.println("myInt is 1");
    }

    //  needed only to run this class
    public static void main(String[] args) {
    }

}

콘솔에 "myInt is 1"이라고 출력합니다.클래스는 인스턴스화하지 않았습니다.

static int B,H;
static boolean flag = true;
static{
    Scanner scan = new Scanner(System.in);
    B = scan.nextInt();
    scan.nextLine();
    H = scan.nextInt();

    if(B < 0 || H < 0){
        flag = false;
        System.out.println("java.lang.Exception: Breadth and height must be positive");
    } 
}

static block은 static data member를 다이내믹하게 초기화하기 위한 모든 기술에 사용됩니다. 또는 static data member static block이 사용되고 있다고 말할 수 있습니다.비정적 데이터 멤버 초기화의 경우 컨스트럭터는 있지만 스태틱 데이터 멤버를 동적으로 초기화할 수 있는 장소는 없기 때문입니다.

Eg:-class Solution{
         // static int x=10;
           static int x;
       static{
        try{
          x=System.out.println();
          }
         catch(Exception e){}
        }
       }

     class Solution1{
      public static void main(String a[]){
      System.out.println(Solution.x);
        }
        }

이제 정적 int x가 동적으로 초기화됩니다.Bcoz는 컴파일러가 Solution.x로 이동할 때 솔루션 클래스와 정적 블록 로드를 로드합니다.따라서 정적 데이터 구성원을 동적으로 초기화할 수 있습니다.

}

언급URL : https://stackoverflow.com/questions/2420389/static-initialization-blocks

반응형