使用注解注册Feature配置时反射获取字段返回null的问题排查
问题排查与解决:反射获取子类字段返回null
问题根因
Java对象的初始化顺序是:父类构造方法执行 → 子类实例字段初始化 → 子类构造方法执行。
你的父类Feature构造方法执行时,子类FeatureChild的setting1字段还未完成初始化(仍为默认值null),因此调用field.get(this)会返回null。
解决方案
方案1:子类构造中调用父类注册方法(推荐)
把反射注册逻辑从父类构造移到单独方法,让子类在自身字段初始化后调用:
修改父类Feature:
public class Feature { protected List<Setting> settings = new ArrayList<>(); protected void registerSettings() { try { Class<SettingAnno> anno = SettingAnno.class; for (Field field : this.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(anno)) { // 若字段为private,需先设置可访问 field.setAccessible(true); Setting setting = (Setting) field.get(this); this.settings.add(setting); } } } catch (Exception e) { e.printStackTrace(); } } public Feature() { // 父类构造不再执行注册逻辑 } }
修改子类FeatureChild:
public final class FeatureChild extends Feature { @SettingAnno("setting1") public final BooleanSetting setting1 = new BooleanSetting(true); public FeatureChild() { super(); // 此时子类字段已完成初始化,调用注册方法 registerSettings(); } }
方案2:使用子类实例初始化块
利用实例初始化块的执行时机(父类构造后、子类构造前)完成注册,可读性略逊于方案1:
public final class FeatureChild extends Feature { @SettingAnno("setting1") public final BooleanSetting setting1 = new BooleanSetting(true); // 实例初始化块,在父类构造后执行 { try { Class<SettingAnno> anno = SettingAnno.class; for (Field field : this.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(anno)) { field.setAccessible(true); Setting setting = (Setting) field.get(this); this.settings.add(setting); } } } catch (Exception e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Kevin_557
相关产品推荐
相关产品推荐

