在具有继承的构造函数中进行反射 (Java)

Reflection in constructor with inheritance (Java)

我无法在 class 构造函数中使用继承进行反射。具体来说,我想获取所有属性值。

这是一个无法正常工作的简单实现的演示:

import java.lang.reflect.Field;

public class SubInitProblem {
  public static void main(String[] args) throws IllegalAccessException {
    Child p = new Child();
  }
}

class Parent {
  public int parentVar = 888888;

  public Parent() throws IllegalAccessException {
    this.showFields();
  }

  public void showFields() throws IllegalAccessException {
    for (Field f : this.getClass().getFields()) {
      System.out.println(f + ": " + f.get(this));
    }
  }
}

class Child extends Parent {
  public int childVar = 999999;

  public Child() throws IllegalAccessException {
    super();
  }
}

这将显示 childVar 为零:

public int Child.childVar: 0
public int Parent.parentVar: 888888

因为还没有初始化。

所以我想我不需要直接使用构造函数,而是让构造函数完成然后然后使用showFields:

import java.lang.reflect.Field;

public class SubInitSolution {
  public static void main(String[] args) throws IllegalAccessException {
    SolChild p = SolChild.make();
  }
}

class SolParent {
  public int parentVar = 888888;

  protected SolParent() {
  }

  public static <T extends SolParent> T make() throws IllegalAccessException {
    SolParent inst = new SolParent();
    inst.showFields();
    return (T) inst;
  }

  public void showFields() throws IllegalAccessException {
    for (Field f : this.getClass().getFields()) {
      System.out.println(f + ": " + f.get(this));
    }
  }

}

class SolChild extends SolParent {
  public int childVar = 999999;

  public SolChild() throws IllegalAccessException {
  }
}

但这不起作用,因为 make 不是 return subclass 的正确类型。 (所以问题是new SolParent();)。

解决这个问题的最佳方法是什么? 我需要所有子classes 来执行showFields,但我不能依赖他们明确地执行它。

您的 showFields 方法需要遍历 class 层次结构,如下所示:

public void showFields() throws IllegalAccessException {
    Class<?> clz = this.getClass();
    while(clz != Object.class) {
        for (Field f : clz.getDeclaredFields()) {
            f.setAccessible(true);
            System.out.println(f + ": " + f.get(this));
        }
        clz=clz.getSuperclass();
    }
}

注意我用的是Class.getDeclaredFields(), not Class.getFields(),因为后者只处理public个字段


这就是您如何以通用方式构建 classes:

public static <T extends SolParent> T make(Class<T> type) throws Exception {
    Constructor<T> constructor = type.getDeclaredConstructor();
    constructor.setAccessible(true);
    T inst = constructor.newInstance();
    inst.showFields();
    return inst;
}

请注意,这仅在您的 SolParent 子类型具有 public 无参数构造函数(或根本没有构造函数)时才有效。