【问题标题】:Java enum get null in static method of my enum classJava枚举在我的枚举类的静态方法中为空
【发布时间】:2020-08-04 17:21:16
【问题描述】:

我有一个枚举类来存储我的消息,我想在其中使用一个静态方法将它们放入一个 hashmap。

但是 NullPointerException 刚刚发生。 我该如何解决?

Msg.java

public enum Msg {

    //Common
    Message1("this"),
    Message2("is"),
    Message3("not"),
    Message4("cool");

    private String message;
    private static HashMap<Msg, String> Msgmap;
    
    private static HashMap<Msg, String> getMsgmap(){
        return Msgmap;
    }
    
    Msg(String msg) {
        this.message = msg;
        if(getMsgmap() == null) {
            setupMsgMap();
        }
    }

    private static void setupMessageMap() {
        Msgmap = new HashMap<Msg, String>();
        for(Msg msg :values()){
            Msgmap.put(msg, msg.message);
        }
    }
    
}

如果我替换

for(Msg msg:values()){
            langmap.put(msg, msg.message);
        }

System.out.println(Message1.message);

也会抛出 NullPointerException

但是如果我尝试在构造函数中打印我的枚举字符串。 它会起作用的。

【问题讨论】:

  • 请提供您的枚举类的完整源代码。
  • 您的代码似乎不完整,我收到编译错误。什么是语言映射?
  • 你在“消息”类中有什么?
  • 你应该遵循 Java 命名约定 变量名和方法名应该用驼峰命名; PascalCase 中的类名;和 UPPER_SNAKE_CASE 中的常量(包括枚举常量)。
  • 对不起,我忘了用 Msg 替换 Lang。已编辑

标签: java enums


【解决方案1】:

如果可以,我建议您使用最终不可变字段。这样你就不用担心线程安全了。

你应该知道的一些信息:

  1. 枚举构造函数被调用的次数与枚举所具有的常量一样多。
  2. 对于具有至少一个常量的枚举,不可能编写将在构造函数之前调用的静态块。
  3. 在这种情况下,您可以在静态块中初始化静态字段。

以下是我的版本,基于@charlie-armstrong 代码:

enum Message { //the class is named "Message"
    Message1("this"),
    Message2("is"),
    Message3("not"),
    Message4("cool"); //line ends in a semicolon

    private static final HashMap<Message, String> Msgmap = new HashMap<>(); //Msgmap is initialized here

    static {
        for (Message msg : values()) { //loop through all the enum constants
            Msgmap.put(msg, msg.message); //add them all to the HashMap
        }
    }

    private final String message;

    Message(String msg) {
        this.message = msg;
        //I don't set up Msgmap in the constructor, because it is still initializing itself here, so we can't possibly add it to a HashMap yet
    }

    public static Map<Message, String> getMsgmap() {
        return Msgmap;
    }
}

【讨论】:

    【解决方案2】:

    好的,您的代码有很多问题。我将首先为您提供代码的注释版本,显示所有错误,然后我将提供一个有效的版本。这是您的代码:

    public enum Msg { //should be called "Message", since it is in Message.java
    
        //Common
        Message1("this"),
        Message2("is"),
        Message3("not"),
        Message4("cool"), //syntax error, the line should end in a semicolon (;)
    
        private String message;
        private static HashMap<Msg, String> Msgmap; //Msgmap is never initialized
        
        private static HashMap<Msg, String> getMsgmap(){
            return Msgmap;
        }
        
        Msg(String msg) { //again, should be named "Message", not "Msg"
            this.message = msg;
            if(getMsgmap() == null) { //this will always be true, because Msgmap is never initialized
                setupMsgMap(); //this will run 4 times (once for every enum value)
            }
        }
    
        private static void setupMessageMap() {
            langmap = new HashMap<Lang, String>(); //syntax error (you didn't declare or infer a type), and the Lang class has not been provided to us, I assume you meant to use the Msg class instead
            for(Lang lang:values()){ //NullPointerException occurs here.  We're still initializing the first enum constant, but you're asking the compiler to loop through ALL the enum constants.  They aren't initialized yet though; they don't actually exist yet.
                langmap.put(lang, lang.lang);
            }
        }
        
    }
    

    这是我更新的代码:

    public enum Message { //the class is named "Message"
        Message1("this"),
        Message2("is"),
        Message3("not"),
        Message4("cool"); //line ends in a semicolon
    
        private String message;
        private static HashMap<Message, String> Msgmap = new HashMap<>(); //Msgmap is initialized here
    
        public static HashMap<Message, String> getMsgmap() {
            return Msgmap;
        }
    
        Message(String msg) {
            this.message = msg;
            //I don't set up Msgmap in the constructor, because it is still initializing itself here, so we can't possibly add it to a HashMap yet
        }
    
        public static void setupMsgMap() { //this will need to be called from outside AFTER initialization
            for (Message msg : values()) { //loop through all the enum constants
                Msgmap.put(msg, msg.message); //add them all to the HashMap
            }
        }
    }
    

    【讨论】:

    • 您可以使用static{} 块来初始化地图。
    • 您可以使用它来初始化地图,但不能填充它,因为静态块在初始化程序之前运行。我只是在声明行初始化它,两者都可以。
    • @polygnome 是对的。请参阅我的回答 stackoverflow.com/a/63252960/12292000stackoverflow.com/a/11419587/12292000
    • @user12292000 是的,你和 polygnome 是对的......我的初始化程序和静态块在我的脑海中以错误的方式出现。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-17
    相关资源
    最近更新 更多