2010-11-16 2 views
1

Учитывая следующие три класса, как я могу использовать отражение для вызова функции инициализации для родительского класса (ов), а затем подкласс:Java Reflection/Generic

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 является сырым типом.

Мне нужно, чтобы вызвать инициализацию иерархии классов, если то, что я передаю в инициализацию, является подклассом элемента.

Что-то вроде следующего:

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

Edit 1:

я не могу параметризировать выше функцию псевдо-другому, чтобы сохранить тип объекта, а затем вызвать функцию мне нужно?

То, что я пытаюсь сделать, заключается в том, чтобы избежать того, чтобы один и тот же метод был переопределен для каждого из моих классов и допустил некоторое наследование для моих объектов страницы Selenium 2. То, что мне нужно сделать, - это возможность интроспекции суперкласса (ов) моего себя и инициализации каждого из моих полей WebElement до запуска тестов в этих полях.

Они впрыскиваются пружиной и еще больше усложняют то, что я разрешаю, чтобы тесты были написаны с использованием языка Spring Expression. Я ленив загружать свои бобы и использовать интерфейс InitializingBean, чтобы попытаться инициализировать мои WebElements до их использования, чтобы избежать NPE.

Мне пришлось обернуть WebElements с помощью специального объекта, чтобы я мог вставлять стратегии местоположения с использованием Spring (мы повторно используем много частей, но у них разные имена идентификаторов/классов в зависимости от того, где они используются в приложении; это было сделано до того, как я пришел сюда и не изменился в это время, несмотря на мои аргументы в пользу последовательности). Например, у нас есть виджет даты с разной детализацией, иногда нам нужен всего месяц, иногда месяц и год и т. Д. Было бы неплохо, если бы я мог использовать абстрактный класс и разбить эти общие черты до их наименее общего знаменателя и оттуда. Для этого мне нужно, чтобы быть в состоянии сделать следующее в своем базовом классе:

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(); 
    } 
} 

ответ

0

Вот мое временное решение, оставляя вопрос открытым, чтобы надеяться собрать несколько лучших ответов, хотя для моего варианта использования.

public abstract class PageObject implements InitializingBean { 
... 
public void afterPropertiesSet() { 
    Class clazz = this.getClass(); 
    do { 
     initializeElements(clazz); 
     clazz = clazz.getSuperclass(); 
    } while (clazz != null); 
} 
2

Вы не можете вызвать метод на определенном уровне. Единственное, что у вас есть доступ к ключевому слову super внутри самого класса.

Чтобы сделать эту работу, вы хотите позвонить super.initialize() из каждого подкласса, а затем просто вызвать его через отражение.

Это не C++, где вы можете указать конкретный метод на определенном уровне иерархии наследования.

+0

Не означает ли это, что я называю super.initialize до тех пор, пока не будет исключено исключение NoSuchMethodException? Это не пахнет правильно. – Scott

+0

Я думаю, вы ошибаетесь в этом. @Scott пытается вызвать методы 'static', а ограничения на вызов переопределенных методов не применяются к статическим методам. –

0

Я не совсем уверен, как параметризовать функцию инициализации в классе Test, так как параметр clazz является сырым типом.

Ничто в вашем примере не требует использования параметра типового типа, поэтому объявите его как Class<?>.

Я не понимаю, что ваши методы Инициализировать действительно пытаются сделать, но есть ряд проблем:

Вы, кажется, есть один initialize метод, который принимает экземпляр (из Element) в качестве аргумента, и другой, который принимает объект Class в качестве аргумента. Это действительно яблоки и апельсины ... и вам нужно объяснить, что вы пытаетесь сделать.

Вашей попытка конкретизации методы содержит следующее:

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

Это никогда не будет вычисляться так, потому что он спрашивает, если какое-то Class объекта является экземпляром из Element класса. (Более того, clazz.getClass().getSuperclass() на самом деле будет таким же, как java.lang.Object.class. Класс объекта Class - java.lang.Class, а его суперкласс - java.lang.Object).

Но я не могу понять, что это должно быть, потому что вы не совсем четко описываете то, что вы пытаетесь достичь.

+0

@aioobe - вы побеждаете. Я его отменил :-) –