Как я могу создать экземпляр класса в Java с обобщениями? - PullRequest
0 голосов
/ 07 марта 2012

Как я могу создать экземпляр класса в java с обобщениями?

Я пытаюсь прочитать данные из файла XML, а затем создать экземпляр объекта, чтобы я мог добавить другие свойства объекта (считанные из файла XML) в объект. Я думал, что самый простой способ (чтобы мне не приходилось читать имена методов класса и находить сеттеры) - это создать экземпляр объекта со всеми значениями в конструкторе.

Я пытаюсь сделать что-то подобное, поэтому мне нужно что-то вроде: T obj = new Object(), но получить класс объектов

    private static final boolean string_field = true;

    private static <T> T getObject(Element e, String[] fieldNames, boolean[] fieldTypes) {
        Object[] values = new Object[fieldNames.length];
        for (int i=0; i<fieldNames.length; i++) {
            values[i] = (fieldTypes[i]==string_field)? getStringValue(e, fieldNames[i])
                    : getIntegerValue(e, fieldNames[i]);
        }
        return new T(values);
    }

Спасибо за ваш совет.

EDIT:

Это мой обновленный код (не проверено):

    public static <T> List<T> populateObjectList(Document xmlDoc, String tagName,
            Class clazz, String[] fieldNames, Class[] fieldTypes) {
        List<T> objList = new ArrayList<T>();
        NodeList nl = xmlDoc.getElementsByTagName(tagName);
        if (nl!=null && nl.getLength()>0) {
            for (int i=0; i<nl.getLength(); i++) {
                Element e = (Element) nl.item(i);
                T t;
                try {
                    t = getObject(e, clazz, fieldNames, fieldTypes);
                    objList.add(t);
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (IllegalArgumentException ex) {
                } catch (InvocationTargetException ex) {
                } catch (NoSuchMethodException ex) {
                }
            }
        }
        return objList;
    }

    private static <T> T getObject(Element e, Class clazz, String[] fieldNames, Class[] fieldTypes)
            throws InstantiationException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchMethodException {
        Object[] initargs = new Object[fieldNames.length];
        for (int i=0; i<fieldNames.length; i++) {
            initargs[i] = (fieldTypes[i].getName().equals("int"))?
                getIntegerValue(e, fieldNames[i])
                : getStringValue(e, fieldNames[i]);
        }
        return (T) clazz.getConstructor(fieldTypes).newInstance(initargs);
    }

Я написал это, чтобы некоторые из вас поняли, что я пытаюсь сделать.

Еще раз спасибо всем за советы.

Ответы [ 4 ]

4 голосов
/ 07 марта 2012

Вы не можете создать экземпляр универсального типа.Обобщения Java имеют раздражающую особенность, называемую стирание типа , что в основном означает, что JVM не знает, какой тип использовался для обобщенного класса или метода во время выполнения.Это для обратной совместимости с предварительно родовыми версиями универсальных классов, такими как коллекции.

Что вы можете сделать, это добавить Class<T> clazz в список параметров, а затем заменить конец метода следующим:

Class<?>[] paramTypes = new Class[values.length];
for (int i = 0; i < paramTypes.length; i++) {
    paramTypes[i] = values[i].getClass();
}
return clazz.getConstructor(paramTypes).newInstance(values);

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

CAVEAT: Это работает, только если типы параметров конструктора точно совпадают с типами объектов.Например, если values состоит из { "Hello", new Integer(2) }, то будет найден только конструктор с подписью SomeClass(String, Integer), а не тот, с подписью SomeClass(Object, Object).

2 голосов
/ 07 марта 2012

Как вы могли бы знать, что T содержит конструктор, который принимает один Object[] аргумент? Способ исправить это - перейти на абстрактную фабрику.

interface ThingFactory { // Choose an appropriate name.
    T create(Object[] values);
}

private static <T> T getObject(
    ThingFactory<T> factory, Element e, String[] fieldNames, boolean[] fieldTypes
) { 
    ...
    return factory.create(values);
}

Теперь T может даже не иметь довольно странного конструктора Object[]. T может быть абстрактным типом. Фабрика может вернуть другой тип в зависимости от аргументов. Возможно, иногда эти продукты являются неизменяемыми объектами, которые можно кэшировать.

1 голос
/ 07 марта 2012

Вы не можете сделать new T(), потому что во время выполнения, T эффективно просто Object.Компилятор использует обобщенные элементы для проверки типов (например, вы не можете поместить Integer в List<String>), но затем выбрасывает обобщенную информацию.Существует одна скомпилированная копия метода для всех типов аргументов, поэтому у него нет возможности узнать, какой тип вы ожидаете, когда он будет создан.

Подробнее о стирании типов читайте.

0 голосов
/ 07 марта 2012

Я действительно не вижу вашей проблемы, нельзя ли использовать obj.getClass?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...