public class Test {
public static void main(String[] args) {
Platform1 p1=Platform1.FACEBOOK; //giving NullPointerException.
Platform2 p2=Platform2.FACEBOOK; //NO NPE why?
}
}
enum Platform1{
FACEBOOK,YOUTUBE,INSTAGRAM;
Platform1(){
initialize(this);
};
public void initialize(Platform1 platform){
switch (platform) {
//platform is not constructed yet,so getting `NPE`.
//ie. we doing something like -> switch (null) causing NPE.Fine!
case FACEBOOK:
System.out.println("THIS IS FACEBOOK");
break;
default:
break;
}
}
}
enum Platform2{
FACEBOOK("fb"),YOUTUBE("yt"),INSTAGRAM("ig");
private String displayName;
Platform2(String displayName){
this.displayName=displayName;
initialize(this);
};
public void initialize(Platform2 platform){
switch (platform.displayName) {
//platform not constructed,even No `NPE` & able to access its properties.
//switch (null.displayName) -> No Exception Why?
case "fb":
System.out.println("THIS IS FACEBOOK");
break;
default:
break;
}
}
}
任何人都可以解释为什么NullPointerException
中有Platform1
但Platform2
中没有preparedStatement
。在第二种情况下,我们如何能够访问枚举对象及其属性,甚至在构造对象之前?
答案 0 :(得分:11)
完全。正如@PeterS在正确构造之前提到的那样使用枚举导致NPE,因为在未构造的枚举上调用了values()方法。
还有一点,我想在此处添加Platform1
和Platform2
两者都尝试在switch()中使用未构造的枚举,但NPE仅在Platform1
中。这背后的原因如下: -
public void initialize(Platform1 platform){
switch (platform) {
来自Platform1
枚举的上面一段代码在交换机中使用platform
枚举对象,其中使用内部$SwitchMap$Platform1[]
数组并初始化此数组values()
方法,因此你得到NPE。但是在Platform2
中,switch (platform.displayName)
是displayName
上的比较,它已经初始化并且发生了字符串比较,因此没有NPE。
以下是反编译代码的片段: -
PLATFORM1
static final int $SwitchMap$Platform1[] =
new int[Platform1.values().length];
PLATFORM2
switch ((str = platform.displayName).hashCode())
{
case 3260:
if (str.equals("fb")) {
答案 1 :(得分:3)
在正确构建枚举之前尝试处理枚举时,不能这样做。 (如在完整的东西中构建)。您会注意到错误正在尝试引用枚举的值部分:
Caused by: java.lang.NullPointerException
at Platform1.values
在处理对象之前,您需要允许对象在内部进行正确的初始化。这将有效:
public static void main(String[] args) {
Platform1 p1=Platform1.FACEBOOK;
p1.initialize(p1);
//Platform1.YOUTUBE giving NullPointerException why?
Platform2 p2=Platform2.FACEBOOK;
//NO NPE
}
enum Platform1{
FACEBOOK,YOUTUBE,INSTAGRAM;
Platform1(){
//initialize(this);
};
显然,您的初始化函数应该重命名,因为它只是报告值。 您的第二个示例提供了值,因此可以正常工作。
来自其中一个Java文档:
枚举声明定义了一个类(称为枚举类型)。枚举 类体可以包括方法和其他字段。编译器 在创建枚举时自动添加一些特殊方法。对于 例如,它们有一个返回数组的静态值方法 按顺序包含枚举的所有值 声明。这种方法通常与之结合使用 for-each构造迭代枚举类型的值。对于 例如,下面的Planet类示例中的代码将迭代 太阳系中的所有行星。
答案 2 :(得分:3)
正如已经指出的那样,枚举上的switch
在内部调用values
方法,但只有在初始化所有枚举常量后才会初始化:
Caused by: java.lang.NullPointerException
at Platform1.values(Test.java:17)
at Platform1$1.<clinit>(Test.java:25)
... 4 more
在Platform2
中,这不会发生,因为字符串中的switch
。
更面向对象的方法是创建一个initialize
方法,构造函数调用该方法并被需要专门初始化的常量覆盖:
enum Platform3 {
FACEBOOK {
@Override
protected void initialize() {
System.out.println("THIS IS FACEBOOK");
}
},
YOUTUBE,
INSTAGRAM;
Platform3() {
initialize();
}
// this acts as the default branch in the switch
protected void initialize() {
System.out.println("THIS IS OTHER PLATFORM: " + this.name());
}
}
答案 3 :(得分:1)
您正在获取NPE,因为您正在引用尚未构建的实例。 Platform1.FACEBOOK
null
是Platform1
,直到构造FACEBOOK
实例的Platform1
构造函数完成。
initialize
构造函数调用switch
,其中包含case
。 switch
中的Platform1.FACEBOOK
读取FACEBOOK
。由于FACEBOOK
的构造函数尚未返回,因此null
引用为空。 Java Language Specification不允许case
作为switch
中的 #include <fstream>
#include <locale>
#include <codecvt>
const locale utf8_locale = locale(locale(), new codecvt_utf8<wchar_t>());
wofstream file(url);
file.imbue(utf8_locale);
file << L"իմբյու" << endl;
,它会像您找到的那样抛出运行时异常。
答案 4 :(得分:1)
以下示例显示了初始化生命周期:
public class Test {
// v--- assign to `PHASE` after creation
static final Serializable PHASE = new Serializable() {{
// v---it is in building and doesn't ready...
System.out.println("building:" + PHASE); //NULL
System.out.println("created:" + this);//NOT NULL
}};
public static void main(String[] args) {
// v--- `PHASE` is ready for use
System.out.println("ready:" + PHASE); //NOT NULL
}
}
简而言之,枚举常量在构建过程中未初始化。换句话说,当前的枚举实例将被分配给关联的常量,直到整个建筑工作完成。
switch语句将调用values()
方法,但枚举常量处于构建状态并且尚未准备好使用。为了避免客户端代码更改其内部$VALUES
数组,values()
将克隆其内部数组,因为枚举常量尚未准备就绪NullPointerException
1}}被抛出。这是字节码values()
方法&amp;静态初始化块:
static {};
10: putstatic #14 // Field FACEBOOK:LPlatform1;
23: putstatic #16 // Field YOUTUBE:LPlatform1;
// putstatic //Other Fields
61: putstatic #1 // Field $VALUES:[LPlatform1;
// `$VALUES` field is initialized at last ---^
public static Platform1[] values();
// v--- return null
0: getstatic #1 // Field $VALUES:[LPlatform1;
// v--- null.clone() throws NullPointerException
3: invokevirtual #2 // Method "[LPlatform1;".clone:()Ljava/lang/Object;
答案 5 :(得分:1)
简答: 调用初始化方法的地方,当枚举类被类加载器(正在进行)加载时被调用,因此您无法访问类级属性,即静态。您可以在哪里访问非staic属性。
<强> 1。当你第一次在代码中引用Enum时,会调用enum的构造函数。
Platform1 p1=Platform1.FACEBOOK;
此行将使用类加载器加载Enum Platform1的类。并且将为该枚举中的每个条目/实例调用构造函数,此处为3。
下面的代码将打印三个哈希码。
enum Platform1{
FACEBOOK,YOUTUBE,INSTAGRAM;
Platform1() {
initialize(this);
};
public void initialize(Platform1 platform){
System.out.println(platform.hashCode()); // it will print three hash codes
switch (platform.hashCode()) {
case 1:
System.out.println(platform);
break;
default:
break;
}
}
}
因此,简而言之,当调用此初始化方法时,Enum类未完全加载且正在进行中。因此,您无法在该时间点访问该枚举的任何静态属性或方法。
<强> 2。当您使用下面的行时,它会调用values()一个静态方法
public void initialize(Platform1 platform){
switch (platform) {
}
}
只需将静态方法更改为某种等效的非静态方法即可。等,
enum Platform1{
FACEBOOK,YOUTUBE,INSTAGRAM;
Platform1() {
initialize(this);
};
public void initialize(Platform1 platform){
System.out.println(platform.hashCode());
switch (platform.toString()) { // toString() is non static method
case "FACEBOOK":
System.out.println(platform);
break;
default:
break;
}
}
}
第3。因此,您的问题的答案是,当Enum类初始化时,您
无法访问任何静态内容
但可以访问非静态内容
因此,以下代码正在为您工作
enum Platform2{
FACEBOOK("fb"),YOUTUBE("yt"),INSTAGRAM("ig");
private String displayName;
Platform2(String displayName){
this.displayName=displayName;
initialize(this);
};
public void initialize(Platform2 platform){
switch (platform.displayName) {
case "fb":
System.out.println("THIS IS FACEBOOK");
break;
default:
break;
}
}
}
<强> 4。如果你将displayName更改为static,那么事情就会中断。
enum Platform2{
FACEBOOK("fb"),YOUTUBE("yt"),INSTAGRAM("ig");
private static String displayName = "FACEBOOK";
Platform2(String displayName){
initialize(this);
};
public void initialize(Platform2 platform){
switch (platform.displayName) {
case "FACEBOOK":
System.out.println(platform);
break;
default:
break;
}
}
}