Java 最终静态字段在第一次使用时为空
Java final static field is null at first usage
有一个 class 应该将日志存储在本地文件中,该文件被硬编码到程序中。
初始化逻辑如下:
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
public class Util {
private static final Logger LOGGER = Logger.getLogger(Util.class.getName());
private static final FileHandler filehandler = createFileHandler();
private static FileHandler createFileHandler(){
FileHandler handler;
try {
handler = new FileHandler("security.log", 0, 1, true);
LOGGER.addHandler(filehandler);
} catch (IOException | SecurityException e) {
handler = null;
LOGGER.log(Level.SEVERE, "Unable to create Security log!");
}
return handler;
}
public static String use_util(){
LOGGER.log(Level.INFO, "Utils are used!");
return "It's just I don't know.. a string, man.";
}
public static void main(String[] args){
System.out.println(Util.use_util());
}
}
然而,在第一次调用 use_util
时出现空指针异常,指出 LOGGER
为空:
$javac Util.java
$java -Xmx128M -Xms16M Util
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
at java.util.logging.Logger.addHandler(Logger.java:1748)
at Util.createFileHandler(Util.java:14)
at Util.<clinit>(Util.java:8)
根据 Java 规范 section 12.4.2 :
Then, initialize the final class variables and fields of interfaces whose values are compile-time >constant expressions (§8.3.2.1, §9.3.1, §13.4.9, §15.28).
...
Next, execute either the class variable initializers and static initializers of the class, or the field >initializers of the interface, in textual order, as though they were a single block.
所以基于此,LOGGER
应该在 fileHandler
之前初始化。尽管如此, LOGGER
在初始化 fileHandler
时似乎为空...
这是为什么?
怎么强制初始化顺序?
Caused by: java.lang.NullPointerException
at java.util.logging.Logger.addHandler(Logger.java:1748)
从我的阅读方式来看,class 字段在这里不是问题。
LOGGER
不为空,执行了对 LOGGER.addHandler()
的调用,但在内部失败。
这是因为您将 filehandler
传递给调用,而不是您刚刚在之前的行中初始化的处理程序 handler
。
由于此时您仍在 filehandler
的初始化执行中,因此它仍然是 null
.
有一个 class 应该将日志存储在本地文件中,该文件被硬编码到程序中。
初始化逻辑如下:
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
public class Util {
private static final Logger LOGGER = Logger.getLogger(Util.class.getName());
private static final FileHandler filehandler = createFileHandler();
private static FileHandler createFileHandler(){
FileHandler handler;
try {
handler = new FileHandler("security.log", 0, 1, true);
LOGGER.addHandler(filehandler);
} catch (IOException | SecurityException e) {
handler = null;
LOGGER.log(Level.SEVERE, "Unable to create Security log!");
}
return handler;
}
public static String use_util(){
LOGGER.log(Level.INFO, "Utils are used!");
return "It's just I don't know.. a string, man.";
}
public static void main(String[] args){
System.out.println(Util.use_util());
}
}
然而,在第一次调用 use_util
时出现空指针异常,指出 LOGGER
为空:
$javac Util.java
$java -Xmx128M -Xms16M Util
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
at java.util.logging.Logger.addHandler(Logger.java:1748)
at Util.createFileHandler(Util.java:14)
at Util.<clinit>(Util.java:8)
根据 Java 规范 section 12.4.2 :
Then, initialize the final class variables and fields of interfaces whose values are compile-time >constant expressions (§8.3.2.1, §9.3.1, §13.4.9, §15.28). ...
Next, execute either the class variable initializers and static initializers of the class, or the field >initializers of the interface, in textual order, as though they were a single block.
所以基于此,LOGGER
应该在 fileHandler
之前初始化。尽管如此, LOGGER
在初始化 fileHandler
时似乎为空...
这是为什么? 怎么强制初始化顺序?
Caused by: java.lang.NullPointerException
at java.util.logging.Logger.addHandler(Logger.java:1748)
从我的阅读方式来看,class 字段在这里不是问题。
LOGGER
不为空,执行了对 LOGGER.addHandler()
的调用,但在内部失败。
这是因为您将 filehandler
传递给调用,而不是您刚刚在之前的行中初始化的处理程序 handler
。
由于此时您仍在 filehandler
的初始化执行中,因此它仍然是 null
.