我知道静态初始化块是如何工作的。
请问有哪些典型用途呢?
当您想在一个地方初始化一个或多个静态变量时,这是很有用的。这是因为您可以使用异常处理,而通过内联初始化是不可能的。
例如:
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所指出的那样,静态初始化块会使代码更难阅读,因此请谨慎使用。静态方法可以更透明地执行相同的操作。
尽量避免使用静态初始化块。相反,您可以使用私有静态初始化函数,这将使您的代码更加清晰。
我将参考@Bozho的示例。
不要这样做:
public static Configuration configuration;
static {
confuguration = new Configuration();
configuration.setSomething(..);
configuration.setSomethingElse(..);
...
}
请使用以下内容代替
public static Configuration configuration = createConfiguration();
public static Configuration configuration = YourConfiguration.create();
它们通常与JNI代码一起使用,以确保加载所需的本地库:
class MyJniConnection {
public static native void myJniCall();
static {
System.load("native.dll");
}
}
为什么需要使用Class.forName()
将驱动程序加载到内存中。答案很简单。根据JDBC规范,所有的JDBC Driver
在Driver
类被加载时都有一个静态块来向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
注册自己。
它们可以用来创建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