1

给定以下三个类,我如何使用反射来调用父类和子类的初始化函数:

public class Test {

    public static void main(String[] args) {
        ExtendedElement ee = new ExtendedElement();
        initialize(ee);
     }

    public static void initialize(Element element) {
        System.out.println(element.getClass());
        initialize(element.getClass());
    }

    public static void initialize(Class clazz) {
        System.out.println(clazz.getClass());
    }
}

public class Element {
    protected String value;
    public String getValue() { return value; }
    public void setValue(String value) { this.value = value; }
}

public class ExtendedElement extends Element {
    protected String extendedValue;
    public void setExtendedValue(String extendedValue) {
        this.extendedValue = extendedValue;
    }
    public String getExtendedValue() { return extendedValue; }
}

我不太确定如何在 Test 类中参数化初始化函数,因为 clazz 参数是原始类型。

如果我传递给 initialize 的是 Element 的子类,我本质上需要的是调用类层次结构的初始化。

类似于以下内容:

public void initialize(Class clazz) { 
    if (Element.class.isInstance(clazz.getClass().getSuperclass()) {
         initialize(clazz.getClass().getSuperclass());
    }
    //Work to call initialize function 
}

编辑1:

我不能对上面的伪函数进行不同的参数化以保留对象的类型,然后调用我需要的函数吗?

我想要做的是避免必须为我的每个类重写相同的方法,并允许我的 Selenium 2 页面对象进行一些继承。我需要做的是能够自省我自己的超类并在对这些字段运行测试之前初始化我的每个 WebElement 字段。

这些是用 spring 注入的,为了进一步复杂化,我允许使用 Spring Expression 语言编写测试。我懒加载我的 bean,并使用 InitializingBean 接口尝试在使用之前初始化我的 WebElements 以避免 NPE。

我必须用自定义对象包装 WebElement,以便我可以使用 spring 注入位置策略(我们重用了很多部分,但它们具有不同的 id/类名,具体取决于它们在应用程序中的使用位置;这是之前完成的对我来说,尽管我主张一致性,但此时不会改变)。例如,我们有一个具有不同粒度的日期小部件,有时我们只需要一个月,有时是月份和年份等......如果我可以使用抽象类并将这些共性分解为它们的最小公分母,那就太好了并从那里延伸。为此,我需要能够在我的基类中执行以下操作:

public abstract class PageObject implements InitializingBean {
    ...
    public void afterPropertiesSet() {
        //Pass in concrete impl we are working with - this allows me to initialize properly
        initializeWebElements(this.getClass());
    }
    ...
    public void initializeWebElements(Class clazz) {
        //This does not grab inherited fields, which also need to be initialized
        for (Field field : clazz.getDeclaredFields()) {
            if (WidgetElement.class == field.getType()) {
                Method getWidgetElement = clazz.getDeclaredMethod("get" +
                    StringUtils.capitalize(field.getName()), new Class [] {});
                    WidgetElement element = 
                      (WidgetElement) getWidgetElement.invoke(this, new Object [] {});
                    element.initElement();
    }
}
4

3 回答 3

2

您不能在特定级别调用方法。唯一的事情是您可以访问super类本身内部的关键字。

为了使这个工作,你想super.initialize()从每个子类中调用,然后通过反射调用它。

这不是 C++,您可以在继承层次结构的特定级别调用特定方法。

于 2010-11-16T03:57:26.987 回答
0

这是我的临时解决方案,尽管为我的用例留下了问题,但希望能收集到一些更好的答案。

public abstract class PageObject implements InitializingBean {
...
public void afterPropertiesSet() {
    Class clazz = this.getClass();
    do {
        initializeElements(clazz);
        clazz = clazz.getSuperclass();
    } while (clazz != null);
}
于 2010-11-16T13:48:40.623 回答
0

我不太确定如何在 Test 类中参数化初始化函数,因为 clazz 参数是原始类型。

您的示例中没有任何内容要求您使用泛型类型参数,因此将其声明为Class<?>.

我不明白您的初始化方法真正想要做什么,但是有很多问题:

您似乎有一个initialize将实例 (of Element) 作为参数的方法,另一个将Class对象作为参数的方法。这真的是苹果和橘子的东西......你需要解释你想要做什么。

您充实该方法的尝试包含以下内容:

Element.class.isInstance(clazz.getClass().getSuperclass())

这永远不会评估为真,因为它询问某个Class对象是否是该类的实例。Element(更重要的是,clazz.getClass().getSuperclass()实际上将与 相同java.lang.Object.classClass对象的类是java.lang.Class,它的超类是java.lang.Object)。

但我无法弄清楚它应该是什么,因为你没有清楚地描述你想要实现的目标。

于 2010-11-16T05:17:44.447 回答