前两天写代码的时候遇到这样的问题
问题
前两天写代码的时候遇到这样的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import com.x.StorageType; import org.apache.log4j.Logger;
import java.util.ArrayList; import java.util.List;
public enum AdditionHandlerManager { INSTANCE;
private final static Logger logger = Logger.getLogger(AdditionHandlerManager.class);
private final List<AdditionHandler> handlers = new ArrayList<>();
AdditionHandlerManager() { register(new BiHandler()); register(new DesignerRealTimeOperateHandler()); }
public void register(AdditionHandler handler) { handlers.add(handler); logger.info(String.format("addition handler %s register success", handler.getClass().getSimpleName())); }
public void action(String table, StorageType type, String content) { for (AdditionHandler handler : handlers) { if (handler.accept(table, type)) { handler.action(content); logger.info(String.format("addition handler %s trigger success", handler.getClass().getSimpleName())); break; } } } }
|
在 register 方法里面,出现了 logger npe 的问题。
思考
起初觉得问题很奇怪,不符合我们对于普通类的常识认知,构造方法的执行,肯定是要后于静态变量初始化的,为什么会出现 npe 的问题。
但是后面仔细一下,就明白了,枚举的底层实现其实相当于静态变量,而且这个静态变量相对于其他静态成员是要先初始化的,从 enum 的写法也可以得出结论。
1 2 3 4 5
| public enum Type{ Apple; private static final String RED = "red"; private String color; }
|
必须先完成 Apple 的定义,才能后续书写其他的静态成员。
那么显然,在第一个静态成员初始化的过程中,其他的静态成员必然没有完成初始化,出现 NPE。
实际的 枚举 代码类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import com.x.StorageType; import org.apache.log4j.Logger;
import java.util.ArrayList; import java.util.List;
public class AdditionHandlerManager { public static final AdditionHandlerManager INSTANCE = new AdditionHandlerManager(); private final static Logger logger = Logger.getLogger(AdditionHandlerManager.class); private final List<AdditionHandler> handlers = new ArrayList<>();
public AdditionHandlerManager() { register(new BiHandler()); register(new DesignerRealTimeOperateHandler()); }
public void register(AdditionHandler handler) { handlers.add(handler); logger.info(String.format("addition handler %s register success", handler.getClass().getSimpleName())); }
public void action(String table, StorageType type, String content) { for (AdditionHandler handler : handlers) { if (handler.accept(table, type)) { handler.action(content); logger.info(String.format("addition handler %s trigger success", handler.getClass().getSimpleName())); break; } } } }
|
这就有疑问了,为什么这样显著的错误,不能在编译器层面去做提示。
搜索时,我发现了 R 大的这篇文 enum 静态成员的初始化,在规范中,jls 8.9.2 中已经对于构造方法中静态变量的引用进行了编译期的校验,但是对应的代码放在其他方法中,在构造方法红进行调用,那么编译器就没有那么智能去挖掘对应存在的问题了。

还是要多看书、规范,来避免一些隐藏的坑点。