記Java類static成員的一個初始化問題

    (代碼裏面的註釋和成員我就省略了)
    如下問題雖然我是在enum裏遇到的,實際上enum也是個Class,放在Class上照樣會出問題。
    事情的原由是項目裏面有個enum,定義了兩個屬性code和description,相似以下結構: java

public enum LogType {
    LOGIN("login", "登錄日誌"), ADMIN("admin", "系統管理日誌");

    private String code = null;
    private String description = null;

    private LogType(String code, String description) {
        this.code = code;
        this.description = description;
    }
}

    可是我在數據庫中存儲的是code的值,就須要一個方法能夠把code轉換成對應的枚舉,這時就想到建立一個成員,在構造函數裏面註冊一下,而後就有了如下的改動,卻編譯報錯: 數據庫

// 增長一個存放code和LogType值對應關係的Map
private static Map<String, LogType> instances = new HashMap<>();

// 原計劃在構造函數中向map添加這個對象自己,卻不能經過編譯
private LogType(String code, String description) {
    // 這行報錯: Cannot refer to the static enum field LogType.instances within an initializer
    instances.put(code, this); 
    this.code = code;
    this.description = description;
} 
    你不是不讓我在構造函數裏面直接使用enum的static成員嗎,那好辦,再改一下:
private static Map<String, LogType> instances = new HashMap<>();

private void registerCode(String code) {
    instances.put(code, this);
}

private LogType(String code, String description) {
    registerCode(code);
    this.code = code;
    this.description = description;
}
    這下總能經過編譯了吧,我又沒在構造函數中直接使用static成員。結果一運行,instances.put(code, this)拋出NullPointerException!!!我不是已經new HashMap<>()了嗎。下來查了下資料,獲得這樣一個說法:
    enum在編譯後,枚舉值和剛纔那個靜態成員instances會轉換爲相似以下代碼的結構:
public static final LogType LOGIN = new LogType("login", "登錄日誌");
public static final LogType ADMIN = new LogType("admin", "系統管理日誌");
private static Map<String, LogType> instances = new HashMap<>();
    對LogType()函數的調用是早於new HashMap<>()這句的執行的。因此NullPointerException就不奇怪了
    好吧,我再改,沒有保證instances被賦值給new HashMap<>()嗎,我加個保證
private static Map<String, LogType> instances = null;

private static Map<String, LogType> getInstances() {
    // 若是instances是null,就給他一個hashMap
    if (instances == null) {
        instances = new HashMap<>();
    }

    return instances;
}


// 調用getInstances()而不是直接使用instances,這樣就保證instances不爲null咯
private void registerCode(String code) {
    getInstances().put(code, this);
}
    一運行,果真能夠了,那繼續寫find方法
public static LogType find(String code) {
    return instances.get(code);
}
    使用的時候,又在find裏面拋出NullPointerException!!!剛剛構造函數的那裏getInstances()明明已經賦值了,我registerCode都放了東西進去了,怎麼可能仍是null,這不科學。
    無法只能開god mode打上斷點單步跟一下咯,一看明明getInstances()有調用,registerCode()的時候instances裏面的值我都看得清清楚楚...
    不過最後又繞回private static Map<String, LogType> instances = null 這句把instances改爲null了...緣由就在這裏,最終去掉這個=null,再測試就沒有任何問題了
private static Map<String, LogType> instances;

    總結,static成員的初始化賦值是有可能在對象的構造函數,這時這些成員值爲null,這在enum和一些單例模式的寫法裏面見到。and...沒事不要亂寫=null。
相關文章
相關標籤/搜索