正如标题所说,两者之间究竟有什么区别
public static String myString = "Hello World!";
和
public static String myString;
static {
myString = "Hello World";
}
除了结构还有什么重要的区别吗?
正如标题所说,两者之间究竟有什么区别
public static String myString = "Hello World!";
和
public static String myString;
static {
myString = "Hello World";
}
除了结构还有什么重要的区别吗?
对于您的示例,没有区别。但正如你所见,
public static String myString = "Hello World!";
只能接受一个表达式来初始化变量。但是,在静态初始化程序(JLS 8.7) 中,可以执行任意数量的语句。例如,可以这样做:
static
{
myString = "Hello";
myString += " ";
myString += "World";
}
对于您的示例,显然没有必要这样做,但是变量的初始化可能需要的不仅仅是一个表达式,可能还有很多语句,因此 Java 制作了静态初始化程序。
静态 {...} 块让您有机会做比在字段声明中所能做的更多的事情。
例如,您可以填写地图的一些详细信息:
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);
}
...
}
静态初始化块和常规静态初始化之间的区别。
在变量初始化的情况下,两者都是相同的。
但是如果我们只想与数据库连接一次或任何您想加载一次的操作。然后在静态块中编写代码,因为无论您创建多少该类型的对象,它只在第一个类加载时执行一次。
编辑 :
你也可以构造一个类似的块:
{
// 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();
}
}
输出:
静止的
非静态块
非静态块
好吧,在您的第一个示例中,变量在同一行上声明和初始化。在你的第二个变量首先被声明,然后被初始化。在第二种情况下,您可以在到达相关初始化块之前进行任意数量的其他静态变量和块初始化。考虑这种情况:
public static String myString = "Hello World!";
public static String yourString = myString;
static {
System.out.println(myString);
System.out.println(yourString);
}
与:
public static String myString ;
public static String yourString = myString;
static {
myString = "Hello World";
}
static {
System.out.println(myString);
System.out.println(yourString);
}
第一个示例的输出:
你好世界 你好世界
第二个示例的输出:
你好世界 空值
使用静态块,您可以更改与声明顺序不同的初始化顺序。
要继续 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);
}
区别在于风格问题。您可能只使用数据库表。
静态变量存储一个值,该值在定义它的类的所有实例(或非实例)之间共享。
静态块是第一次加载 Class 时执行的一段代码。
“关于范围,静态块只能在同一个类中访问”,“而静态变量可以从任何类访问”
通常,静态变量的值在其定义的类的所有实例(或非实例)之间共享,其中静态块是在类首次加载时执行的一段代码。功能上没有区别。
最重要的功能在这里没有明确回答,这真的很令人惊讶。
是的,您可以有多条线路。但这有什么意义呢?您还可以在内联静态初始化分配中仅使用一次对工厂方法的调用。( static public final MyType mySPVar = factoryCreateObject();
)
所以让我们关注static public final
变量:
但是,如果该方法(或您的多行中的任何一条)抛出Exception
s 甚至Throwable
s 怎么办?
Checked Exceptions
(不是源自RuntimeException
)Unchecked Exceptions
那可以是RuntimeException
Throwable
s,如Error
初始化程序块(静态和非静态)最重要的方面是能够进行本地化的单个异常处理,该异常处理仍然授予其他方法无法提供的独占/特权访问。
通过独占/特权访问,我解决了以下问题
并在这里反对其他一些答案:关于干净的代码,静态和可公开访问的字段应该是最终的——即使不是不可变的。这是初始化程序块最有效的地方。
现在让我们看看其他情况:
对于任何其他情况,例如
不同的解决方案要好得多:
if(myObj == null) {myObj = new Something();} return myObj;
(在这里考虑同步!)附录:
这里所有的讨论都考虑(静态)类变量,但这里写的大多数观点也与(非静态)对象成员变量密切相关。