Java Generics: доступ к универсальному типу во время выполнения

Я ищу доступ к общему типу объявленного поля во время выполнения. Ранее у меня сложилось впечатление, что это невозможно из-за стирания типа Java. Однако это не должно быть так, поскольку некоторые известные фреймворки используют универсальный тип через отражение во время выполнения.

в качестве примера Guice реализует поставщика на основе универсального типа, который вы предоставляете:

public class Injectable{

    @Inject
    private Provider<SomeType> someTypeProvider;

}

Как получить доступ к "SomeType" generic атрибут поля или любого такого типа/метода/etc через API отражения?

кроме того, было бы полезно также знать, как получить доступ к этим атрибутам универсального типа через API обработчика аннотаций Java 6.

спасибо.

Edit:

спасибо всем за отличные подсказки. Я нашел способ сделать это, используя ссылки хайлема, в частности, на статью Пренкова Отражение Java: Дженерики!--18-->.

вот ответ, который я искала:

/**
 * @author John Ericksen
 */
public class TypeReflectionExample {

    public class SomeType{}

    public class Injectable{
        @Inject  private Provider<SomeType> someTypeProvider;
    }

    public static void main(String[] args){

        try {
            Field providerField = Injectable.class.getDeclaredField("someTypeProvider");

            Type genericFieldType = providerField.getGenericType();

            if(genericFieldType instanceof ParameterizedType){
                ParameterizedType aType = (ParameterizedType) genericFieldType;
                Type[] fieldArgTypes = aType.getActualTypeArguments();
                for(Type fieldArgType : fieldArgTypes){
                    Class fieldArgClass = (Class) fieldArgType;
                    System.out.println("fieldArgClass = " + fieldArgClass);
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }   
}

результаты:

fieldArgClass = тест класса.TypeReflectionExample$SomeType

то же самое можно сделать для методов, конструкторов, расширений/реализаций суперкласса и т. д.

я награждаю хайлема, так как его пост привел меня к этому решению, даже если он прямо не ответил на мой вопрос.

4 ответов


Это правда, что дженерики обычно не известны во время выполнения в Java, потому что они реализованы с стиранием типа.

Отражающие Дженерики?

тем не менее, вы можете извлечь некоторую ценную информацию о заявленных видов (Не типы объектов среды выполнения), как представлено в статье Яна Роберстона Отражающие Дженериков и статья Пренкова Отражение Java: Дженерики!--10-->.

фон на дженерики и тип стирания

дженерики, введенные при сохранении обратной совместимости на исходном двоичном уровне qnd, следовательно, некоторые их ограничения, такие как:

  • невозможность иметь форму короткой руки без хотя бы какого-то индикатора поддержки дженериков (здесь так называемый оператор алмазного <>),
  • невозможность проверки универсальных типов на runtime, потому что они должны были быть реализованы с помощью Стирания Типа.

Более Дальнеишее Чтение

  • из Java Технические Характеристики Языка (JLS):
  • из хороших вопросов StackOverflow:
  • другие:

  • Ну, почему бы тебе посмотрите, что guice делает? Источник является общедоступным.

    Guice делает эти вещи на многих уровнях. Один, который особенно выделяется тип литералов.

    ключевым моментом здесь является то, что в то время как типы составлен использование стирания типа (так что есть только один класс для каждого типа), все еще существует несколько Type объекты, которые знают, используемых генериков. Однако оптимизирован код самостоятельно этого (поскольку он был скомпилирован для класса, а не для типа).

    посмотрите на Java API ParameterizedType.

    Итак, хотя это правильно, что Java Generics реализованы "стиранием типа" на класс уровень, это не полностью держится на


    я использовал это год или около того назад. Это может помочь вам

    Type typeOfSrc = type(YourClass.class, clazz);
    
    // type(C, A1,...,An) => C<A1,...,An>
    static ParameterizedType type(final Class raw, final Type... args)
    {
        return new ParameterizedType()
        {
            public Type getRawType(){ return raw; }
    
            public Type[] getActualTypeArguments(){ return args; }
    
            public Type getOwnerType(){ return null; }
        };
    }
    

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


    Я считаю, что guice использует TypeLiteral для инкапсуляции общей информации в отдельный объект.