静态初始化程序块和常规静态初始化之间的区别

时间:2013-03-18 19:51:57

标签: java static initialization

正如标题所说,

之间究竟有什么区别
public static String myString = "Hello World!";

public static String myString;

static {
    myString = "Hello World";
}

除了结构之外还有什么重要的区别吗?

9 个答案:

答案 0 :(得分:7)

对于你的例子,没有区别。但正如你所看到的,

public static String myString = "Hello World!";

只能接受一个表达式来初始化变量。但是,在static initializer(JLS 8.7)中,可以执行任意数量的语句。例如。可以这样做:

static
{
    myString = "Hello";
    myString += " ";
    myString += "World";
}

对于您的示例,显然没有必要这样做,但是变量的初始化可能不仅仅是表达式,也许是许多语句,因此Java创建了静态初始化器。

答案 1 :(得分:3)

  

静态初始化程序块与常规静态初始化之间的区别。

如果变量初始化两者都相同。

但是如果我们只想连接一次数据库或者你想加载一次的任何操作。然后在静态块中编写代码,因为无论您创建的类型对象有多少,它在第一次类加载时只执行一次。

编辑:

您还可以构建一个类似的块:

{
    // Do Something...
}

示例:

public class Demo {

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

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

    public static void main(String[] args) {
        Demo demo = new Demo();
        Demo demo2 = new Demo();
    }
}

<强>输出:

静态

非静态阻止

非静态阻止

答案 2 :(得分:3)

静态{...}块让您有机会比在现场声明中做的更多。

例如,您可以填写地图的一些细节:

private static final Map<String, String> data = new HashMap<String, String>();

static {
    data.put("A", "Hello");
    data.put("B", "There");
    data.put("C", "You");
}

有时您可能还需要在实例化之前获取数据(来自文件,数据库等):

public class Foo {
    private static final Person person;

    static {
        InputStream personData = Foo.class.getResourceAsStream("something.txt");
        person = new Person(personData);
    }
    ...
}

答案 3 :(得分:2)

好吧,在你的第一个例子中,变量在同一行上声明并初始化。在您的第二个变量首先声明,然后初始化。在第二种情况下,您可以在进入相关初始化块之前进行任意数量的其他静态变量和块初始化。考虑这种情况:

public static String myString = "Hello World!";
public static String yourString = myString;
static {
    System.out.println(myString);
    System.out.println(yourString);
}

VS

public static String myString ;
public static String yourString = myString;

static {
    myString = "Hello World";
}

static {
    System.out.println(myString);
    System.out.println(yourString);
}

第一个例子的输出:

Hello World
Hello World

第二个例子的输出:

Hello World
null

答案 4 :(得分:2)

使用静态块,您可以将初始化的顺序更改为与声明顺序不同。

答案 5 :(得分:2)

要继续Scott Stanchfield所写的内容,您可以使用Collections.unmodifiableXXX()方法来保证安全,但Google Guava等库可能会减少这种安全性。考虑:

public static final Map<String, String> CAPITALS;
static {
    Map<String, String> map = new HashMap<>(); //Java 7.
    map.put("NY", "Albany");
    map.put("MD", "Annapolis");
    map.put("VA", "Richmond");
    map.put("CT", "Hartford");
    // 46 more states
    CAPITALS = Collections.unmodifiableMap(map);
}

当然,拥有一个52行的静态块可能会让人迷失方向,因此您可能会将静态块转换为静态块。

public static final Map<String, String> CAPITALS = capitals();
private static Map<String, String> capitals() {
    Map<String, String> map = new HashMap<>(); //Java 7.
    map.put("NY", "Albany");
    map.put("MD", "Annapolis");
    map.put("VA", "Richmond");
    map.put("CT", "Hartford");
    // 46 more states
    return Collections.unmodifiableMap(map);
}

区别在于风格问题。您可能只需使用数据库表。

答案 6 :(得分:1)

静态变量存储在其定义的类的所有实例(或非实例)之间共享的值。

静态块是在首次加载Class时执行的代码段。

“关于范围,静态块只能在同一个类中”,“而静态变量可以从任何类访问”

答案 7 :(得分:1)

通常,静态变量的值在定义的类的所有实例(或非实例)之间共享,其中静态块是在首次加载Class时执行的代码段。功能上没有区别。

答案 8 :(得分:1)

这里没有明确回答最重要功能真的很令人惊讶。

是的,您可以有多行。但这有什么意义呢?您也可以在内联静态初始化分配中仅使用一次对工厂方法的调用。 (static public final MyType mySPVar = factoryCreateObject();)

那么让我们关注 static public final 变量:

但是如果该方法(或您的多行中的任何一行)抛出 Exception 甚至 Throwable 怎么办?

  • Checked Exceptions(不是源自RuntimeException
  • Unchecked Exceptions 可以
    • 源自RuntimeException
    • 或派生自其他 Throwable,例如 Error

初始化块(静态和非静态)的最重要的方面是能够执行本地化的个别异常处理,这仍然授予其他方法无法提供的独占/特权访问

通过独占/特权访问,我可以解决

的问题
  • 是在这个中运行的第一个代码(在静态变量初始化器之后),所以我们有一个真正纯粹的状态
  • 成为代码块中唯一的地方,您可以在其中分配最终变量(当然,除非您使用反射)
  • 不必处理本地化同步,因为
    • 每个特定类的静态初始化方法永远不会与自身并行运行
    • 在正常的 Java 条件下(没有反射字节码编织/注入魔法;JVM允许的事情,而不是普通的Java),每个静态初始化程序保证只运行一次。

并反对这里的其他一些答案:关于干净的代码,静态和可公开访问的字段应该是最终的 - 如果甚至不是一成不变的。这是初始化块最有效的地方。

现在让我们看看其他情况:

对于任何其他场景,例如

  • (能够)稍后(非最终)更改变量
  • 或者让它只能通过一个方法来访问(变量不是公共的,以及一个Getter方法)

不同的解决方案会更好:

  • 为了稍后在Setter Method上更改变量,应该使用控制变量/类/对象的状态
  • 为了仅通过一种方法访问变量,还可以使用延迟初始化,类似 if(myObj == null) {myObj = new Something();} return myObj; 的东西(考虑 同步 这里!)

附录:

这里的所有讨论都考虑(静态)类变量,但这里写的大多数要点也与(非静态)对象成员变量密切相关。