Static Initialization Blocks

前端 未结 14 1259
暗喜
暗喜 2020-11-22 01:56

As far as I understood the \"static initialization block\" is used to set values of static field if it cannot be done in one line.

But I do not understand why we ne

14条回答
  •  粉色の甜心
    2020-11-22 02:28

    It is a common misconception to think that a static block has only access to static fields. For this I would like to show below piece of code that I quite often use in real-life projects (copied partially from another answer in a slightly different context):

    public enum Language { 
      ENGLISH("eng", "en", "en_GB", "en_US"),   
      GERMAN("de", "ge"),   
      CROATIAN("hr", "cro"),   
      RUSSIAN("ru"),
      BELGIAN("be",";-)");
    
      static final private Map ALIAS_MAP = new HashMap(); 
      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 aliases; 
      private Language(String... aliases) { 
        this.aliases = Arrays.asList(aliases); 
      } 
    } 
    

    Here the initializer is used to maintain an index (ALIAS_MAP), to map a set of aliases back to the original enum type. It is intended as an extension to the built-in valueOf method provided by the Enum itself.

    As you can see, the static initializer accesses even the private field aliases. It is important to understand that the static block already has access to the Enum value instances (e.g. ENGLISH). This is because the order of initialization and execution in the case of Enum types, just as if the static private fields have been initialized with instances before the static blocks have been called:

    1. The Enum constants which are implicit static fields. This requires the Enum constructor and instance blocks, and instance initialization to occur first as well.
    2. static block and initialization of static fields in the order of occurrence.

    This out-of-order initialization (constructor before static block) is important to note. It also happens when we initialize static fields with the instances similarly to a Singleton (simplifications made):

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

    What we see is the following output:

    Static Block 1
    Constructor
    Static Block 2
    In Main
    Constructor
    

    Clear is that the static initialization actually can happen before the constructor, and even after:

    Simply accessing Foo in the main method, causes the class to be loaded and the static initialization to start. But as part of the Static initialization we again call the constructors for the static fields, after which it resumes static initialization, and completes the constructor called from within the main method. Rather complex situation for which I hope that in normal coding we would not have to deal with.

    For more info on this see the book "Effective Java".

提交回复
热议问题