据我所知,“静态初始化块”是用来设置静态字段的值,如果它不能在一行中完成。

但我不明白为什么我们需要一种特殊的积木。例如,我们将一个字段声明为静态(没有赋值)。然后写几行代码,生成并赋值给上面声明的静态字段。

为什么我们需要这些行在一个特殊的块,如:static{…}?


当前回答

在静态块中构造对象之前,可以为一个类执行一次代码。

E.g.

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

其他回答

在静态块中构造对象之前,可以为一个类执行一次代码。

E.g.

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

这里有一个例子:

  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”被省略了。

重要的是要理解类在运行时从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是1打印到控制台。

如果它们不在静态初始化块中,它们会在哪里?如何声明一个只用于初始化的局部变量,并将其与字段区分开来?例如,你想怎么写:

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

如果第一个和第二个不在一个块中,它们看起来就像字段。如果它们在一个前面没有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;
    }
}

... 但是当你希望在同一个块中分配多个变量时,或者没有变量时(例如,如果你只是想记录一些东西-或者可能初始化一个本机库),这就不起作用了。

所以你有一个静态字段(它也被称为“类变量”,因为它属于类而不是类的实例;换句话说,它与类而不是与任何对象相关联),你想初始化它。所以如果你不想创建这个类的实例,你想操纵这个静态字段,你可以用三种方式来做:

1-在声明变量时初始化它:

static int x = 3;

2-有一个静态初始化块:

static int x;

static {
 x=3;
}

有一个类方法(静态方法)来访问类变量并初始化它: 这是上述静态块的替代方案;你可以写一个私有静态方法:

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

为什么要用静态初始化块而不是静态方法呢?

这取决于你的项目需要什么。但是你必须知道静态初始化块只被调用一次,类方法的唯一优点是,如果你需要重新初始化类变量,它们可以被重用。

假设在程序中有一个复杂的数组。你初始化它(例如使用for循环),然后这个数组中的值将在整个程序中改变,但在某个时候你想重新初始化它(回到初始值)。在这种情况下,您可以调用私有静态方法。如果你不需要在程序中重新初始化这些值,你可以只使用静态块,不需要静态方法,因为你以后不会在程序中使用它。

注意:静态块是按照它们在代码中出现的顺序调用的。

示例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
 }

}