問題描述
最近版本組織清理編譯告警,其中有這麼一條比較有意思,之前沒見過,拿出來說一說
“serializable class anonymous com.demo.Main$1 has no definition of serialVersionUID”
編譯告警指向了這段程式碼:
private static List<String> defaultAttrList = new ArrayList<String>() {
{
add(ResourceConsts.RES_NAME);
add(ResourceConsts.RES_TYPE);
add(ResourceConsts.RES_IP);
add(ResourceConsts.RES_VERSION);
}
};
乍一看好像沒什麼問題,我用雙大括號的方式定義並初始化了一個ArrayList
,往裡面塞了幾個值,程式碼簡潔易懂。
但問題並沒有看起來那麼簡單,原因就在雙大括號。
探究
雙大括號的寫法實際上建立了一個匿名類,我們將原始檔編譯後也會發現,生成了一個Main$1.class
的檔案,它就對應這個匿名類。反編譯後的程式碼如下:
class Main$1 extends ArrayList<String> {
Main$1() {
this.add("1");// 10
}// 11
}
可以看到,我們建立了一個名為Main$1
的匿名類,繼承自ArrayList
,而ArrayList
的類定義如下:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
// ......
}
正是因為ArrayList
實現了Serializable
介面,所以Main$1
也需要定義serialVersionUID
。
解決方法
既然是由於匿名類引起的編譯告警,我們可以幹掉匿名類,用靜態域來初始化List
,像下面這樣即可消除告警:
private static List<String> defaultAttrList = new ArrayList<>();
static {
defaultAttrList.add(ResourceConsts.RES_NAME);
defaultAttrList.add(ResourceConsts.RES_TYPE);
defaultAttrList.add(ResourceConsts.RES_IP);
defaultAttrList.add(ResourceConsts.RES_VERSION);
}