NullPointerException | enum构造函数中的`this`导致NPE

22 java enums constructor nullpointerexception java-8

public class Test {
    public static void main(String[] args) {
        Platform1 p1=Platform1.FACEBOOK; //giving NullPointerException.
        Platform2 p2=Platform2.FACEBOOK; //NO NPE why?
    }
}
Run Code Online (Sandbox Code Playgroud)
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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释我为什么会出现NullPointerExceptionPlatform1但不是在Platform2.在第二种情况下,我们如何能够访问枚举对象及其属性,甚至在构造对象之前?

Neh*_*ari 11

究竟.正如@PeterS在正确构造之前提到的那样使用枚举导致NPE,因为在未构造的枚举上调用了values()方法.

还有一点,我想在此添加,Platform1并且Platform2两者都试图在switch()中使用未构造的枚举,但NPE仅在Platform1.这背后的原因如下: -

 public void initialize(Platform1 platform){
        switch (platform) {
Run Code Online (Sandbox Code Playgroud)

来自Platform1enum的上面一段代码是在使用platform内部$SwitchMap$Platform1[]数组的switch中使用enum对象并且使用了初始化这个数组values()方法,因此你获得了NPE.但是Platform2,switch (platform.displayName)在比较displayName中已经初始化并且发生字符串比较因此没有NPE.

以下是反编译代码的片段: -

PLATFORM1

 static final int $SwitchMap$Platform1[] =
            new int[Platform1.values().length];
Run Code Online (Sandbox Code Playgroud)

PLATFORM2

switch ((str = platform.displayName).hashCode())
    {
    case 3260: 
      if (str.equals("fb")) {
Run Code Online (Sandbox Code Playgroud)


Pet*_*erS 3

当您在正确构建枚举之前尝试对其进行操作时,您不能这样做。(就像在完整的构建中一样)。您会注意到错误试图引用枚举的值部分:

Caused by: java.lang.NullPointerException
    at Platform1.values
Run Code Online (Sandbox Code Playgroud)

在处理对象之前,您需要允许该对象在内部正确初始化。这将起作用:

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);
    };
Run Code Online (Sandbox Code Playgroud)

显然,您的初始化函数应该重命名,因为它只是报告值。您的第二个示例提供了值,因此可以正常工作。

来自 Java 文档之一:

枚举声明定义了一个类(称为枚举类型)。枚举类主体可以包含方法和其他字段。编译器在创建枚举时会自动添加一些特殊方法。例如,它们有一个静态值方法,该方法返回一个数组,其中包含按声明顺序排列的所有枚举值。此方法通常与 for-each 构造结合使用来迭代枚举类型的值。例如,下面 Planet 类示例中的代码会迭代太阳系中的所有行星。