Дженерики и Class.forName

Это неподготовлено, но не является этим, для чего был Кузнечик ?

22
задан dogbane 14 November 2009 в 09:29
поделиться

5 ответов

Я думаю, что первый метод должен выглядеть примерно так:

public static <T> T create(final String className, Class<T> ifaceClass) 
throws ClassNotFoundException {
    final Class<T> clazz = Class.forName(className).asSubclass(ifaceClass);
    return create(clazz); 
}

Вы не можете выполнить приведение типов с использованием параметра типа ... без этих надоедливых предупреждений о безопасности типов.

] Между прочим, если вы проигнорируете эти предупреждения, метод create может создать экземпляр некоторого класса, несовместимого с фактическим типом, используемым вызывающей стороной. Это может позже привести к неожиданному исключению ClassCastException; например, когда экземпляр назначен.


РЕДАКТИРОВАТЬ: @Pascal указывает, что нам нужно добавить приведение типов, чтобы сделать эту компиляцию; т.е.

Class<T> clazz = (Class<T>) Class.forName(className).asSubclass(ifaceClass);

К сожалению, нам также необходимо добавить аннотацию @SuppressWarnings.

32
ответ дан 29 November 2019 в 04:57
поделиться

Я думаю, это потому, что Class.forName (..) не параметризован для T. Когда вы запускаете автозаполнение eclipse, оно предполагает возврат clazz.newInstance () Объект. Итак, сохраните состав и добавьте @SuppressWarnings. Если вы не используете метод должным образом (например, String str = Utils.create ("java.util.ArrayList"); ), то возникнет исключение ClassCastException , но это нормально .

2
ответ дан 29 November 2019 в 04:57
поделиться

Второй метод хорош.


Но для первого в качестве параметра можно передать любое имя класса.

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

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

Поэтому я бы сказал , что весь метод не имеет смысла .


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

public static <T> T create(final Class<T> superType, final String className) {
  try {
    final Class<?> clazz = Class.forName(className);
    final Object object = clazz.newInstance();
    if (superType.isInstance(object)) {
      return (T)object; // safe cast
    }
    return null; // or other error 
  } // catch and other error code
}
2
ответ дан 29 November 2019 в 04:57
поделиться

Даже если вы можете заставить приведенный выше код работать, метод конструктора newInstance () предполагает конструктор с нулевым аргументом.

Если у класса его нет, то есть конструктор с нулевым аргументом класса, который вы пытаетесь создать, был явно объявлен закрытым или пакетным, в зависимости от того, откуда вызывается метод, вы получите исключение IllegalAccessException. Что-то, что можно добавить к предварительному условию, если оно сработает.

Конструктор с нулевым аргументом класса, который вы пытаетесь создать, был явно объявлен частным или пакетным, в зависимости от того, откуда вызывается метод, вы получите исключение IllegalAccessException. Что-то, что можно добавить к предварительному условию, если оно сработает.

Конструктор с нулевым аргументом класса, который вы пытаетесь создать, был явно объявлен частным или пакетным, в зависимости от того, откуда вызывается метод, вы получите исключение IllegalAccessException. Что-то, что можно добавить к предварительному условию, если оно сработает.

0
ответ дан 29 November 2019 в 04:57
поделиться

Вы не можете ограничить параметр типа, чтобы он содержал тип с именем className. Следовательно, вызывающий может предоставить любой тип вашей функции create (String), что, конечно, небезопасно по типу.

Поскольку вы не можете статически принудительно обеспечить, чтобы возвращаемый экземпляр реализует какой-либо интерфейс (без того, чтобы вызывающий сообщал вам, передав соответствующий Class object), я бы обошелся без дженериков и приводил вызывающего абонента к любому типу, который он ожидал.

public static Object create(final String className) {
    try {
        final Class<?> clazz = Class.forName(className);
        return create(clazz); 
    }
    catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

Затем вызывающий может написать:

Foo foo = (Foo) create("my.cool.FooBar");

вместо

Foo foo = create("my.cool.FooBar", Foo.class);
1
ответ дан 29 November 2019 в 04:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: