Разница между полем # getAnnotations() и полем # getDeclaredAnnotations()

JavaDoc говорит следующее:

AccessibleObject # getDeclaredAnnotations:

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

Поле # getAnnotes:

Возвращает все аннотации, присутствующие в этом элементе. (Возвращает массив нулевой длины, если этот элемент не имеет аннотаций.) Вызывающий этого метода может свободно изменять возвращенный массив; это не повлияет на массивы, возвращенные другим абонентам.

Поскольку getAnnotations наследуется от класса java.lang.reflect.AccessibleObject, у него есть объекты Field.

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

Ответы

Ответ 1

В исходном коде дается ответ:

выдержка из java.lang.reflect.AccessibleObject:

/**
 * @since 1.5
 */
public Annotation[] getAnnotations() { 
    return getDeclaredAnnotations();
}

/**
 * @since 1.5
 */
public Annotation[] getDeclaredAnnotations()  {
    throw new AssertionError("All subclasses should override this method");
}

И так как поле не переопределяет getAnnotations(): getDeclaredAnnotations().

Таким образом, оба метода делают то же самое при вызове объекта java.lang.reflect.Field. (так что JavaDoc ошибочен, на мой взгляд)

в другом случае это java.lang.Class, который переопределяет оба метода (и делает то, что говорит JavaDoc ;)):

/**
 * @since 1.5
 */
public Annotation[] getAnnotations() { 
    initAnnotationsIfNecessary();
    return AnnotationParser.toArray(annotations);
}

/**
 * @since 1.5
 */
public Annotation[] getDeclaredAnnotations()  {
    initAnnotationsIfNecessary();
    return AnnotationParser.toArray(declaredAnnotations);
}

Ответ 2

Это наоборот. getDeclaredAnnotations() - как говорят документы - это единственный метод, который игнорирует унаследованные аннотации.

Ниже приведен фрагмент, который демонстрирует разницу:

public class Test1 {
    public static void main(String[] args) {
        Test3 test = new Test3();

        for (Annotation annotation : test.getClass().getAnnotations()) {
            System.out.println("Class getAnnotations: " + annotation);
        }

        for (Annotation annotation : test.getClass().getDeclaredAnnotations()) {
            System.out.println("Class getDeclaredAnnotations: " + annotation);
        }

        for (Field field : test.getClass().getFields()) {
            for (Annotation annotation : field.getAnnotations()) {
                System.out.println("Field getAnnotations: " + annotation);
        }

        for (Annotation annotation : field.getDeclaredAnnotations()) {
            System.out.println("Field getDeclaredAnnotations: " + annotation);
        }
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface CustomAnnotation {
    String value();
}

@CustomAnnotation("Class")
class Test2 {
    @CustomAnnotation("Field") public String testString;
}

 class Test3 extends Test2 {} 

Результатом будет "getAnnotations:

Class getAnnotations: @test.CustomAnnotation(value=Class)
Field getAnnotations: @test.CustomAnnotation(value=Field)
Field getDeclaredAnnotations: @test.CustomAnnotation(value=Field)

Вы видите, что Class getDeclaredAnnotations() пуст, потому что класс Test3 не имеет самих аннотаций, только унаследованных от Test2.

Из Javadoc для @Inherited:

Указывает, что тип аннотации автоматически унаследован. Если в объявлении типа аннотации присутствует унаследованная мета-аннотация, а пользователь запрашивает тип аннотации в объявлении класса, а объявление класса не имеет аннотации для этого типа, то суперкласс класса автоматически запрашивается для типа аннотации. Этот процесс будет повторяться до тех пор, пока не будет найдена аннотация для этого типа или не будет достигнута вершина иерархии классов (объект). Если у суперкласса нет аннотации для этого типа, тогда запрос будет указывать, что этот класс не имеет такой аннотации. Обратите внимание, что этот тип мета-аннотации не действует, если аннотированный тип используется для аннотации чего-либо, кроме класса. Обратите внимание также, что эта мета-аннотация позволяет только унаследовать аннотации от суперклассов; аннотации на реализованные интерфейсы не влияют.

Ответ 3

getDeclaredAnnotations() предоставляет прямые реализованные аннотации только в том случае, когда getAnnotations() предоставляет прямые реализации, а также наследуемые аннотации (@Inherited) из своего родительского класса.