Overview of Java Built-in Annotations – Java内置注解的概述

最后修改: 2017年 12月 31日

1. Overview


In this article, we’ll talk about a core feature of the Java language – the default annotations available in the JDK.


2. What an Annotation Is


Simply put, annotations are Java types that are preceded by an “@” symbol.


Java has had annotations ever since the 1.5 release. Since then, they’ve shaped the way we’ve designed our applications.


Spring and Hibernate are great examples of frameworks that rely heavily on annotations to enable various design techniques.


Basically, an annotation assigns extra metadata to the source code it’s bound to. By adding an annotation to a method, interface, class, or field, we can:


  1. Inform the compiler about warnings and errors
  2. Manipulate source code at compilation time
  3. Modify or examine behavior at runtime

3. Java Built-in Annotations


Now that we’ve reviewed the basics, let’s take a look at some annotations that ship with core Java. First, there are several that inform compilation:


  1. @Override
  2. @SuppressWarnings
  3. @Deprecated
  4. @SafeVarargs
  5. @FunctionalInterface
  6. @Native

These annotations generate or suppress compiler warnings and errors. Applying them consistently is often a good practice since adding them can prevent future programmer error.


The @Override annotation is used to indicate that a method overrides or replaces the behavior of an inherited method.


@SuppressWarnings indicates we want to ignore certain warnings from a part of the code. The @SafeVarargs annotation also acts on a type of warning related to using varargs.


The @Deprecated annotation can be used to mark an API as not intended for use anymore. Moreover, this annotation has been retrofitted in Java 9 to represent more information about the deprecation.

@Deprecated注解可用于将某个API标记为不打算再使用。此外,在Java 9中,该注解已被改装,以表示有关废弃的更多信息。

For all these, you can find more detailed information in the articles linked.


3.1. @FunctionalInterface


Java 8 allows us to write code in a more functional way.

Java 8允许我们以一种更实用的方式编写代码。

Single Abstract Method interfaces are a big part of this. If we intend a SAM interface to be used by lambdas, we can optionally mark it as such with @FunctionalInterface:


public interface Adder {
    int add(int a, int b);

Like @Override with methods, @FunctionalInterface declares our intentions with Adder.


Now, whether we use @FunctionalInterface or not, we can still use Adder in the same way:


Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);

But, if we add a second method to Adder, then the compiler will complain:


public interface Adder { 
    // compiler complains that the interface is not a SAM
    int add(int a, int b);
    int div(int a, int b);

Now, this would’ve compiled without the @FunctionalInterface annotation. So, what does it give us?


Like @Override, this annotation protects us against future programmer error. Even though it’s legal to have more than one method on an interface, it isn’t when that interface is being used as a lambda target. Without this annotation, the compiler would break in the dozens of places where Adder was used as a lambda. Now, it just breaks in Adder itself.

@Override一样,这个注解可以保护我们免受未来程序员的错误。尽管在一个接口上有多个方法是合法的,但当该接口被用作 lambda 目标时就不合法了。如果没有这个注释,编译器会在Adder被用作λ的几十个地方中断。现在,它只是在Adder 本身中发生故障。

3.2. @Native


As of Java 8, there is a new annotation in the java.lang.annotation package called NativeThe @Native annotation is only applicable to fields. It indicates the annotated field is a constant that may be referenced from the native code. For instance, here’s how it’s used in the Integer class:

从 Java 8 开始,在 java.lang.annotation 包中有一个新的注解,叫做 Native@Native注解仅适用于字段。它表示被注解的字段是一个常量,可以从本地代码中引用。例如,下面是它在Integer类中的使用方法。

public final class Integer {
    @Native public static final int MIN_VALUE = 0x80000000;
    // omitted

This annotation can also serve as a hint for the tools to generate some auxiliary header files.


4. Meta-Annotations


Next, meta-annotations are annotations that can be applied to other annotations.


For example, these meta-annotations are used for annotation configuration:


  1. @Target
  2. @Retention
  3. @Inherited
  4. @Documented
  5. @Repeatable

4.1. @Target


The scope of annotations can vary based on the requirements. While one annotation is only used with methods, another annotation can be consumed with constructor and field declarations.


To determine the target elements of a custom annotation, we need to label it with a @Target annotation.


@Target can work with 12 different element types. If we look at the source code of @SafeVarargs, then we can see that it must be only attached to constructors or methods:


@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {

4.2. @Retention


Some annotations are meant to be used as hints for the compiler, while others are used at runtime.


We use the @Retention annotation to say where in our program’s lifecycle our annotation applies.


To do this, we need to configure @Retention with one of three retention policies:


  1. RetentionPolicy.SOURCE – visible by neither the compiler nor the runtime
  2. RetentionPolicy.CLASS – visible by the compiler
  3. RetentionPolicy.RUNTIME – visible by the compiler and the runtime

If no @Retention annotation is present on the annotation declaration, then the retention policy defaults to RetentionPolicy.CLASS.


If we have an annotation that should be accessible at runtime:


public @interface RetentionAnnotation {

Then, if we add some annotations to a class:


@Generated("Available only on source code")
public class AnnotatedClass {

Now we can reflect on AnnotatedClass to see how many annotations are retained:


public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
    AnnotatedClass anAnnotatedClass = new AnnotatedClass();
    Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
    assertThat(annotations.length, is(1));

The value is 1 because @RetentionAnnotation has a retention policy of RUNTIME while @Generated doesn’t.


4.3. @Inherited


In some situations, we may need a subclass to have the annotations bound to a parent class.


We can use the @Inherited annotation to make our annotation propagate from an annotated class to its subclasses.

我们可以使用@Inherited 注解来使我们的注解从一个被注解的类传播到其子类。

If we apply @Inherited to our custom annotation and then apply it to BaseClass:


public @interface InheritedAnnotation {

public class BaseClass {

public class DerivedClass extends BaseClass {

Then, after extending the BaseClass, we should see that DerivedClass appears to have the same annotation at runtime:


public void whenAnnotationInherited_thenShouldExist() {
    DerivedClass derivedClass = new DerivedClass();
    InheritedAnnotation annotation = derivedClass.getClass()
    assertThat(annotation, instanceOf(InheritedAnnotation.class));

Without the @Inherited annotation, the above test would fail.


4.4. @Documented


By default, Java doesn’t document the usage of annotations in Javadocs.


But, we can use the @Documented annotation to change Java’s default behavior.


If we create a custom annotation that uses @Documented:


public @interface ExcelCell {
    int value();

And, apply it to the appropriate Java element:


public class Employee {
    public String name;

Then, the Employee Javadoc will reveal the annotation usage:

然后,Employee Javadoc将揭示注释的用法。

Field Detail

4.5. @Repeatable


Sometimes it can be useful to specify the same annotation more than once on a given Java element.


Before Java 7, we had to group annotations together into a single container annotation:

在Java 7之前,我们必须把注解组合到一个容器注解中。

    @Schedule(time = "15:05"),
    @Schedule(time = "23:00")
void scheduledAlarm() {

However, Java 7 brought a cleaner approach. With the @Repeatable annotation, we can make an annotation repeatable:

然而,Java 7带来了一种更简洁的方法。通过@Repeatable注解,我们可以使一个注解可重复使用

public @interface Schedule {
    String time() default "09:00";

To use @Repeatable, we need to have a container annotation, too. In this case, we’ll reuse @Schedules:


public @interface Schedules {
    Schedule[] value();

Of course, this looks a lot like what we had before Java 7. But, the value now is that the wrapper @Schedules isn’t specified anymore when we need to repeat @Schedule:

当然,这看起来很像我们在Java 7之前的情况。但是,现在的价值在于,当我们需要重复@Schedule时,包装器@Schedules不再被指定。

@Schedule(time = "15:05")
@Schedule(time = "23:00")
void scheduledAlarm() {

Because Java requires the wrapper annotation, it was easy for us to migrate from pre-Java 7 annotation lists to repeatable annotations.

因为Java需要包装器注解,所以我们很容易从Java 7之前的注解列表迁移到可重复注解。

5. Conclusion


In this article, we’ve talked about Java built-in annotations that every Java developer should be familiar with.


As always, all the examples of the article can be found over on GitHub.