静态初始化块的使用

9

我知道静态初始化块是如何工作的。
请问有哪些典型用途呢?

7个回答

10

当您想在一个地方初始化一个或多个静态变量时,这是很有用的。这是因为您可以使用异常处理,而通过内联初始化是不可能的。

例如:

public static ImageIcon defaultIcon = ImageIO.read(..);

可以用以下方式初始化

public static ImageIcon defaultIcon;
static {
   try {
       defaultIcon = ImageIO.read(..);
   } catch (IOException ex){
     System.out.println("No default icon available");
   }
}

另一个应用是复杂初始化。例如,如果一个条目需要多行代码才能初始化。假设您有一个配置:

public static Configuration configuration;
static {
     confuguration = new Configuration();
     configuration.setSomething(..);
     configuration.setSomethingElse(..);
     ...
}

第三种用法是初始化一些外部API基础架构。来自我的当前项目的一个例子:

static {
    org.apache.xml.security.Init.init();
}

但是,正如Mykola Golubyev所指出的那样,静态初始化块会使代码更难阅读,因此请谨慎使用。静态方法可以更透明地执行相同的操作。


如果您在哪个类中使用了“security.Init.init()”的示例? - Mykola Golubyev
API要求这样做。请参阅http://santuario.apache.org/Java/api/org/apache/xml/security/Init.html。 - Bozho

5

尽量避免使用静态初始化块。相反,您可以使用私有静态初始化函数,这将使您的代码更加清晰。

我将参考@Bozho的示例。

不要这样做:

public static Configuration configuration;
static {
     confuguration = new Configuration();
     configuration.setSomething(..);
     configuration.setSomethingElse(..);
     ...
}

请使用以下内容代替

public static Configuration configuration = createConfiguration();

或者
public static Configuration configuration = YourConfiguration.create();

1
同意。使用如上所述的块会在单元测试中产生严重问题。 - gpampara

3

它们通常与JNI代码一起使用,以确保加载所需的本地库:

class MyJniConnection {

    public static native void myJniCall();

    static {
        System.load("native.dll");
    }
}

2

JDBC驱动程序是一个流行的例子

为什么需要使用Class.forName()将驱动程序加载到内存中。答案很简单。根据JDBC规范,所有的JDBC DriverDriver类被加载时都有一个静态块来向DriverManager注册自己。就像这样:

static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
}

因此,当你使用MySQL驱动程序编写代码时(例如这里):

Class.forName("org.gjt.mm.mysql.Driver");

类加载器尝试加载和链接org.gjt.mm.mysql.Driver类,如果成功,则静态初始化块将被执行,并且Driver会向DriverManager注册自己。


2
  • 初始化一个集合静态字段,例如Map、List、Set等
  • 初始化基于setter的静态对象

1

它们可以用来创建DSL,就像JMock一样。例如,设置一个期望,即用户将被保存到数据库中:

Mockery context = new Mockery();
final Database database = context.mock(Database.class);    
...
context.checking(new Expectations() {{
    oneOf(database).save(user);
}});

// Rest of the test

0
  • 静态块:当我们想在类加载时执行代码时,可以将代码放在静态块中...
  • 初始化块:当我们想在类对象初始化时执行代码时,可以将代码放在初始化块中...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接