【问题标题】:Reflection in constructor with inheritance (Java)具有继承的构造函数中的反射(Java)
【发布时间】:2017-03-14 14:27:19
【问题描述】:

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

这是一个无效的简单实现的演示:

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 没有为子类返回正确的类型。 (所以问题是new SolParent();)。

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

【问题讨论】:

  • 在你的第二个例子中,为什么要实现 make 方法?为什么不直接做new SolChild().showFields();
  • 不要从构造函数中调用此类方法。它们不参与初始化,因此不属于构造函数。
  • @Mark 让每个构造函数调用某个方法,这个方法需要放在那个构造函数中。但是编译器不能让某人在他们的构造函数中添加特定的方法调用(即使他们扩展了你的类)。我有一种感觉,我们正面临着X/Y problem
  • @Mark 一个更简单的替代方法是使用initstart 方法并记录在使用对象之前需要调用它的事实。所以基本上为这些类型的对象创建一个生命周期合约。
  • 你不能使SolParent()构造函数private。如果你这样做,子类是不可能的。

标签: java inheritance constructor java-8 static-typing


【解决方案1】:

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

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(),不是Class.getFields(),因为后者只处理公共字段。


这就是您可以以通用方式构造类的方式:

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 子类型具有公共无参数构造函数(或根本没有构造函数)时才有效。

【讨论】:

  • make 仍将创建父实例,而不是子实例。
  • 虽然这是有道理的,但我认为这不是问题所在。父母的属性已经找到,孩子的属性还没有初始化。编辑:关于您的编辑,我不确定Class&lt;T&gt; type 是什么,我会调查并回来
  • @Mark 表示你可以传递任何扩展 SolParent 的类,包括 SolChild。
  • @Holger 好的,把答案改成直接调用构造函数,包括私有构造函数
  • @Mark 你当然可以在方法中添加参数并将这些参数用于构造函数解析(像 Spring 这样的框架),但是很快事情​​就会变得非常不稳定
猜你喜欢
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2011-09-09
  • 2010-12-11
  • 1970-01-01
  • 2012-10-09
相关资源
最近更新 更多