Java包装类中静态final字段意外返回null问题排查
静态final字段初始化异常:ImportSpecificationWrapper.TSV返回null问题排查
问题概述
在ImportSpecificationWrapper类中,静态final字段TSV本应持有ImportSpecification实例,但实际访问时意外返回null。初始化过程无异常抛出,也不存在其他干扰性的静态初始化器。本地构建最小复现示例未重现该问题,但在项目环境中确有发生。因无法修改ImportSpecification类,采用包装类的方式扩展其类型。
相关代码
ImportSpecificationWrapper类
public class ImportSpecificationWrapper { private final ImportSpecification importSpecification; public static final ImportSpecification TSV = new ImportSpecification("TSV", "TSV"); public ImportSpecificationWrapper(ImportSpecification importSpecification) { this.importSpecification = importSpecification; } public String getType() { return importSpecification.getType(); } public String getFriendlyType() { return importSpecification.getFriendlyType(); } @Override public int hashCode() { return importSpecification.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof ImportSpecificationWrapper) { return importSpecification.equals(((ImportSpecificationWrapper) obj).importSpecification); } return false; } public static ImportSpecificationWrapper getInstance(String type) { if (TSV.getType().equals(type)) { return new ImportSpecificationWrapper(TSV); } return new ImportSpecificationWrapper(ImportSpecification.getInstance(type)); } public static Collection<ImportSpecification> getTypes() { return ImportSpecification.getTypes(); } }
ImportSpecification类
public class ImportSpecification implements Serializable, BroadleafEnumerationType { private static final long serialVersionUID = 1L; private static final LinkedHashMap<String, ImportSpecification> TYPES = new LinkedHashMap<>(); public static final ImportSpecification CSV = new ImportSpecification("CSV", "CSV"); public static final ImportSpecification JSON = new ImportSpecification("JSON", "JSON"); public static final ImportSpecification ASSET_ARCHIVE = new ImportSpecification("ASSET_ARCHIVE", "Asset Archive"); public static ImportSpecification getInstance(final String type) { return TYPES.get(type); } public static Collection<ImportSpecification> getTypes() { return Collections.unmodifiableCollection(TYPES.values()); } private String type; private String friendlyType; public ImportSpecification() { //do nothing } public ImportSpecification(final String type, final String friendlyType) { this.friendlyType = friendlyType; setType(type); } @Override public String getType() { return type; } @Override public String getFriendlyType() { return friendlyType; } private void setType(final String type) { this.type = type; if (!TYPES.containsKey(type)) { TYPES.put(type, this); } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (obj != null && getClass().isAssignableFrom(obj.getClass())) { ImportSpecification other = (ImportSpecification) obj; return new EqualsBuilder() .append(type, other.type) .build(); } return false; } }
临时解决方法
在ImportSpecificationWrapper类中添加如下静态初始化块,强制提前加载ImportSpecification类后,TSV字段不再返回null:
static { try { Class.forName("path.to.ImportSpecification"); } catch (ClassNotFoundException e) { log.error("Could not find class path.to.ImportSpecification"); } }
原因分析
该问题源于Java类初始化顺序的异常交互:
项目环境中ImportSpecificationWrapper的类加载时机早于ImportSpecification。当初始化ImportSpecificationWrapper.TSV时,会触发ImportSpecification的类初始化,但此时ImportSpecification内部的静态成员(如TYPES集合、内置静态常量)仍处于初始化过程中,导致创建ImportSpecification实例时出现半初始化状态,最终使得TSV字段被意外赋值为null。
添加静态初始化块手动调用Class.forName,会强制ImportSpecification类完成全部静态初始化流程,之后再初始化ImportSpecificationWrapper.TSV,从而避免了类初始化过程中的异常交互。
内容的提问来源于stack exchange,提问作者user3533413
相关产品推荐
相关产品推荐

