Statyczne Bloki Inicjalizacji

O ile dobrze zrozumiałem, "statyczny blok inicjalizacji" służy do ustawiania wartości pola statycznego, jeśli nie można tego zrobić w jednej linii.

Ale nie rozumiem, dlaczego potrzebujemy do tego specjalnego bloku. Na przykład deklarujemy pole jako statyczne (bez przypisania wartości). A następnie napisz kilka linii kodu, które generują i przypisują wartość do wyżej zadeklarowanego pola statycznego.

Po co nam te linie w specjalnym bloku jak: static {...}?

Author: Andrew Tobilko, 2010-03-10

13 answers

Blok niestatyczny:

{
    // Do Something...
}

Jest wywoływana za każdym razem, gdy instancja klasy jest konstruowana. Blok statyczny jest wywoływany tylko raz, gdy klasa jest zainicjalizowana, bez względu na to, ile obiektów tego typu utworzysz.

Przykład:

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();
    }
}

To drukuje:

Static
Non-static block
Non-static block
 371
Author: Frederik Wordenskjold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-23 22:10:10

Gdyby nie byli w statycznym bloku inicjalizacji, gdzie by byli? Jak zadeklarować zmienną, która miała być lokalna tylko dla celów inicjalizacji i odróżnić ją od pola? Na przykład, jak ty chcesz napisać:

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;
    }
}

Gdyby first i second nie znajdowały się w bloku, wyglądałyby jak pola. Gdyby znajdowały się w bloku bez static przed nim, liczyłby się jako blok inicjalizacji instancji zamiast statycznego bloku inicjalizacji, więc jest on wykonywany raz na skonstruowaną instancję, a nie raz w sumie.

Teraz w tym konkretnym przypadku, można użyć statycznej metody zamiast:

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;
    }
}

... ale to nie działa, gdy istnieje wiele zmiennych, które chcesz przypisać w tym samym bloku, lub Żadna (np. jeśli chcesz po prostu coś zalogować - lub może zainicjować natywną bibliotekę).

 115
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-10 05:47:56

Oto przykład:

  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");
  }

Kod w sekcji "static"zostanie wykonany w czasie ładowania klasy, zanim jakiekolwiek instancje klasy zostaną skonstruowane (i zanim jakiekolwiek statyczne metody zostaną wywołane z innego miejsca). W ten sposób możesz mieć pewność, że zasoby klasowe są gotowe do użycia.

Możliwe jest również posiadanie niestatycznych bloków inicjujących. Działają one jak rozszerzenia do zestawu metod konstruktora zdefiniowanych dla danej klasy. Wyglądają jak inicjalizator statyczny bloki, z wyjątkiem słowa kluczowego "static" jest pominięty.

 90
Author: Pointy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-10 20:48:53

Jest to również przydatne, gdy nie chcesz przypisywać wartości do niczego, na przykład ładując jakąś klasę tylko raz podczas wykonywania.

Np.

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

Hej, jest jeszcze jedna korzyść, możesz użyć jej do obsługi wyjątków. Wyobraź sobie, że getStuff() tutaj rzuca Exception który naprawdę należy do bloku catch:

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

Wtedy static inicjalizacja jest tutaj użyteczna. Tam możesz obsłużyć wyjątek.

Innym przykładem jest robienie rzeczy później, które nie można tego zrobić podczas przypisywania:

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);
    }
}

Aby wrócić do przykładu sterownika JDBC, każdy przyzwoity sterownik JDBC sam używa inicjalizatora static, aby zarejestrować się w DriverManager. Zobacz też to i to odpowiedź.

 44
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:47

Powiedziałbym, że static block jest tylko składniowym cukrem. Nie możesz nic zrobić z static blokiem, a nie z niczym innym.

Do ponownego wykorzystania niektórych przykładów zamieszczonych tutaj.

Ten fragment kodu może zostać napisany ponownie bez użycia inicjalizatora static.

Metoda # 1: Z static

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

Metoda # 2: Bez 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;
}
 11
Author: user1508893,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-28 05:20:49

Istnieje kilka rzeczywistych powodów, dla których musi istnieć:

  1. inicjalizacja static final członków, których inicjalizacja może rzucić wyjątek
  2. inicjalizacja static final członków o obliczonych wartościach

Ludzie mają tendencję do używania bloków static {} jako wygodnego sposobu inicjowania rzeczy, od których Klasa zależy również w środowisku runtime - takich jak upewnienie się, że dana klasa jest załadowana (np. sterowniki JDBC). Można to zrobić na inne sposoby; jednak dwie rzeczy, które ja wspomnianie powyżej można zrobić tylko za pomocą konstrukcji takiej jak static {} block.

 9
Author: D.Shawley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-07 11:43:39

Możesz wykonać bity kodu raz dla klasy, zanim obiekt zostanie zbudowany w statycznych blokach.

Np.

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());
  }
}
 7
Author: Pierre-Antoine LaFayette,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-10 20:46:00

Powszechnym błędem jest myślenie, że blok statyczny ma dostęp tylko do pól statycznych. W tym celu chciałbym pokazać poniżej fragment kodu, który dość często używam w rzeczywistych projektach (skopiowany częściowo z innej odpowiedzi w nieco innym kontekście):

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); 
  } 
} 

Tutaj inicjalizator jest używany do utrzymywania indeksu (ALIAS_MAP), aby odwzorować zestaw aliasów z powrotem do oryginalnego typu enum. Jest on przeznaczony jako rozszerzenie wbudowanej metody valueOf dostarczonej przez Enum siebie.

Jak widać, statyczny inicjalizator uzyskuje dostęp nawet do pola private aliases. Ważne jest, aby zrozumieć, że blok static ma już dostęp do instancji wartości Enum (np. ENGLISH). Dzieje się tak dlatego, że kolejność inicjalizacji i wykonania w przypadku typów Enum , tak jakby pola static private zostały zainicjalizowane instancjami przed wywołaniem bloków static:

  1. stałe Enum, które są domkniętymi polami statycznymi. To wymaga konstruktora Enum i bloków instancji, a także inicjalizacji instancji.
  2. static blokowanie i inicjalizacja pól statycznych w kolejności występowania.

Ta niekonwencjonalna inicjalizacja (konstruktor przed static blokiem) jest ważna do odnotowania. Dzieje się tak również wtedy, gdy inicjalizujemy statyczne pola instancjami podobnie jak Singleton (uproszczone):

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();
  }
}

Widzimy następujące Wyjście:

Static Block 1
Constructor
Static Block 2
In Main
Constructor

Wyczyść jest to, że statyczna inicjalizacja może mieć miejsce przed konstruktorem, a nawet po:

Po prostu dostęp do Foo w głównej metodzie powoduje załadowanie klasy i rozpoczęcie statycznej inicjalizacji. Ale jako część inicjalizacji statycznej ponownie wywołujemy konstruktory dla pól statycznych, po czym wznawia inicjalizację statyczną i uzupełnia konstruktor wywołany z głównej metody. Dość skomplikowana sytuacja, dla której mam nadzieję, że w normalnym kodowanie, z którym nie musielibyśmy sobie radzić.

Więcej informacji na ten temat można znaleźć w książce " Effective Java ".

 6
Author: YoYo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 21:13:33

Jeśli zmienne statyczne muszą być ustawione w czasie wykonywania, to Blok static {...} jest bardzo pomocny.

Na przykład, jeśli chcesz ustawić statyczny element na wartość, która jest przechowywana w pliku konfiguracyjnym lub bazie danych.

Jest również przydatne, gdy chcesz dodać wartości do statycznego członka Map, ponieważ nie możesz dodać tych wartości w początkowej deklaracji członka.

 3
Author: Marcus Leon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-10 20:40:51

Więc masz statyczne pole (nazywane również "zmienną klasy", ponieważ należy do klasy, a nie do instancji klasy; innymi słowy jest powiązane z klasą, A nie z jakimkolwiek obiektem) i chcesz je zainicjować. Jeśli więc nie chcesz tworzyć instancji tej klasy i chcesz manipulować tym statycznym polem, możesz to zrobić na trzy sposoby:

1-po prostu zainicjalizuj ją, gdy zadeklarujesz zmienną:

static int x = 3;

2-mają statyczne inicjowanie blok:

static int x;

static {
 x=3;
}

3-mają metodę klasy (metodę statyczną), która uzyskuje dostęp do zmiennej klasy i inicjalizuje ją: jest to alternatywa dla powyższego bloku statycznego; możesz napisać prywatną metodę statyczną:

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

Dlaczego używasz statycznego bloku inicjującego zamiast statycznych metod?

To naprawdę zależy od tego, czego potrzebujesz w swoim programie. Ale musisz wiedzieć, że statyczny blok inicjujący jest wywoływany raz i jedyną zaletą metody klasy jest to, że mogą być ponownie użyte później, jeśli trzeba ponownie uruchomić zmienną klasy.

Załóżmy, że masz złożoną tablicę w swoim programie. Inicjalizujesz go (używając dla pętli na przykład), a następnie wartości w tej tablicy zmienią się w całym programie, ale w pewnym momencie chcesz ją ponownie uruchomić (wróć do wartości początkowej). W tym przypadku można wywołać prywatną metodę statyczną. W przypadku, gdy nie potrzebujesz w swoim programie do ponownej inicjalizacji wartości, możesz po prostu użyć bloku statycznego i nie ma potrzeby statyczna metoda, ponieważ nie użyjesz jej później w programie.

Uwaga: statyczne bloki są wywoływane w kolejności, w jakiej występują w kodzie.

Przykład 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
 }

}

Przykład 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
 }

}
 2
Author: Randa Sbeity,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-29 03:51:15

Jako uzupełnienie, jak powiedział @Pointy

Kod w sekcji "static" zostanie wykonany przy obciążeniu klasy czasu, zanim jakiekolwiek instancje klasy zostaną skonstruowane (i przed dowolne metody statyczne są wywoływane z innego miejsca).

Ma dodawać System.loadLibrary("I_am_native_library") do bloku statycznego.

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

Gwarantuje, że żadna natywna metoda nie zostanie wywołana przed załadowaniem odpowiedniej biblioteki do pamięci.

Według loadLibrary z oracle :

Jeśli ta metoda zostanie wywołana więcej niż raz o tej samej nazwie biblioteki, drugie i kolejne wywołania są ignorowane.

Więc dość nieoczekiwanie, wprowadzenie systemu.loadLibrary nie jest używane, aby uniknąć wielokrotnego ładowania biblioteki.

 0
Author: Gearon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 14:18:51

Najpierw musisz zrozumieć, że same klasy aplikacji są tworzone jako instancje do obiektów java.class.Class podczas wykonywania. To jest, gdy twoje bloki statyczne są uruchamiane. Więc możesz to zrobić:

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) {
    }

}

I wyświetli" myInt is 1 " na konsoli. Zauważ, że nie stworzyłem żadnej klasy.

 0
Author: eosimosu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-20 16:24:31

Blok statyczny jest używany dla dowolnej technologii do inicjalizacji statycznego elementu danych w sposób dynamiczny, lub możemy powiedzieć, że dla dynamicznej inicjalizacji statycznego elementu danych blok statyczny jest używany..Ponieważ dla inicjalizacji statycznych prętów danych mamy konstruktor, ale nie mamy miejsca, w którym możemy dynamicznie inicjalizować statyczne pręty danych

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);
        }
        }

Teraz mój statyczny int x inicjalizuje się dynamicznie ..Bcoz kiedy kompilator przejdzie do rozwiązania.x załaduje klasę rozwiązania i blok statyczny obciążenie przy obciążeniu klasowym time..So możemy dynamicznie inicjalizować ten statyczny element danych..

}

 -1
Author: Arun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-14 16:45:21