Создать шаблонный метод, который использует отражение для создания объекта - PullRequest
1 голос
/ 22 декабря 2011

У меня есть метод шаблона, который должен создавать экземпляры объектов класса с заданной строкой имени класса, используя отражение. Случай немного сложен, поскольку возвращаемый класс является реализацией интерфейса, который также использует переменную типа. Я хотел бы передать строку имени класса и тип переменной типа интерфейса и создать объект класса. Вот пример подписи метода:

<T> Class<? extends Foo<T>> 
createClassObject(String className, Class<T> classTypeVariable);

Возможно ли реализовать этот метод в Java 1.5 без каких-либо предупреждений или какого-либо использования аннотации @SuppressWarnings?

РЕДАКТИРОВАТЬ: пример подписи метода отредактирован благодаря комментарию Томаса.

Ответы [ 3 ]

3 голосов
/ 22 декабря 2011

Нет, этого невозможно достичь без каких-либо предупреждений или использования аннотации @SuppressWarnings. Это потому, что Class.forName () будет напечатан как Class. Любая попытка привести его к чему-то более конкретному (например, к чему-то по линии Class<? extends Foo<T>>) приведет к предупреждению, связанному с удалением типа. То же самое происходит, если вы пытаетесь привести Class.forName (). NewInstance ().

Тем не менее, я думаю, что этот метод является ярким примером для положительного использования @SuppressWarnings. Я не вижу проблем с использованием этой аннотации в таких случаях. Конечно, вы можете добавить некоторую логику, которая проверяет, что Class.forName(className) действительно расширяет Foo<T>, чтобы убедиться, что кастинги звучат правильно. Обратите внимание, что эти проверки во время выполнения не делают метод более хрупким: когда в вашем методе есть вызов Class.forName(), у вас уже есть потенциальная ошибка типа времени выполнения.

1 голос
/ 22 декабря 2011

Если возвращаемый класс должен быть универсальным (Bar<T> extends Foo<T> или еще много чего), то я вполне уверен, что это невозможно, поскольку (из-за стирания) система типов не может проверить во время выполнения, если класс, который Class.forName(...) вернул, является Class<Bar<T>>, а не Class<Bar<U>> или чем-то еще. (На самом деле существует только один Class объект, представляющий все Bar<...> типы, но система типов не имеет представления для этого, поэтому она делает вид, что Class<Bar<T>> и Class<Bar<U>> - это совершенно отдельные объекты с разными типами.) Самое близкое, что вы можете получить, это что-то вроде этого:

<T> Class<? extends Iterable<T>> createClassObject
        (final String className, final Class<T> clazz) throws Exception
    { return Class.forName(className).asSubclass(getIterableTClass(clazz)); }

@SuppressWarnings("unchecked")
<T> Class<? extends Iterable<T>> getIterableTClass(final Class<T> clazz)
    { return (Class<? extends Iterable<T>>)(Class<?>)Iterable.class; }

, где вы используете непроверенное приведение, чтобы заставить компилятор думать, что у него достаточно информации о Foo<T> (в данном случае Iterable<T>) для проверки asSubclass.

Однако, если возвращаемый класс не должен быть универсальным (Bar extends Foo<String> или еще много чего), то я не уверен; Я никогда не имел дело с частями рефлексии, которые занимаются этим, хотя я знаю, что они существуют. Я почти уверен, что они позволят вам изучить достаточно иерархии наследования Bar, чтобы определить, действительно ли она расширяет Foo<String>, но я действительно не знаю, дадут ли они вам способ сделать компилятор знайте, что вы сделали это.

0 голосов
/ 22 декабря 2011

Да, это может быть сделано.В среде IDE NetBeans 7 я не получаю никаких предупреждений.

ИСПРАВЛЕНИЕ: извините, это не может работать, отсутствует построение классов.Конечно, вы можете использовать ClassLoader, прокси-класс или ASM.

public class Bar<T> extends Foo<T> {
}

Это действительно логично и просто.Подсказка, вероятно, выполняет цепочку newInstance ().

    public <T> Class<? extends Foo<T>> createClassObject(String className, Class<T> classTypeVariable) {
    try {
        Class<? extends Class> resultType = Bar.class.getClass();
        return resultType.getConstructor(classTypeVariable).newInstance();
    } catch (InstantiationException ex) {
        throw new IllegalStateException(ex);
    } catch (IllegalAccessException ex) {
        throw new IllegalStateException(ex);
    } catch (IllegalArgumentException ex) {
        throw new IllegalStateException(ex);
    } catch (InvocationTargetException ex) {
        throw new IllegalStateException(ex);
    } catch (NoSuchMethodException ex) {
        throw new IllegalStateException(ex);
    } catch (SecurityException ex) {
        throw new IllegalStateException(ex);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...