# Java 注解教程

> 原文： [https://beginnersbook.com/2014/09/java-annotations/](https://beginnersbook.com/2014/09/java-annotations/)

[Java 注解](https://docs.oracle.com/javase/tutorial/java/annotations/index.html)允许我们将元数据信息添加到我们的源代码中，尽管它们不是程序本身的一部分。注解从 JDK 5 添加到 java 中。注解对它们注解的代码的操作没有直接影响（即它不影响程序的执行）。

在本教程中，我们将介绍以下主题：注解的使用，如何应用注解，Java 中可用的预定义注解类型以及如何创建自定义注解。

## 注解有什么用？

**1）编译器指令**：Java 中有三种内置注解（`@Deprecated`，`@Override`和`@SuppressWarnings`），可用于向编译器提供某些指令。例如，`@override`注解用于指示编译器注解方法是否覆盖该方法。有关这些内置注解的更多信息，请参阅本文的下一部分。

**2）编译时教程**：注解可以为编译器提供编译时指令，软件构建工具可以进一步使用它来生成代码，XML 文件等。

**3）运行时指令**：我们可以定义在运行时可用的注解，我们可以使用 [java 反射](https://docs.oracle.com/javase/tutorial/reflect/)访问它们，并可用于在运行时向程序发出指令。我们将在稍后的同一篇文章的帮助下讨论这个问题。

## 注解基础知识

注解始终以符号`@`开头，后跟注解名称。符号`@`向编译器指示这是一个注解。

对于例如`@Override`
这里@符号表示这是一个注解，而`Override`是这个注解的名称。

**我们可以在哪里使用注解？**

注解可以应用于类，接口，方法和字段。例如，以下注解正在应用于该方法。

```java
@Override
void myMethod() { 
    //Do something 
}
```

这个注解在这里做的正是在下一节中解释的，但简单来说它指示编译器`myMethod()`是一个覆盖超类方法（`myMethod()`）的重写方法。

## Java 中的内置注解

Java 有三个内置注解：

*   `@Override`
*   `@Deprecated`
*   `@SuppressWarnings`

#### 1）`@Override`：

在覆盖子类中的方法时，我们应该使用此批注来标记该方法。这使得代码可读并避免维护问题，例如：在更改父类的方法签名时，必须更改子类中的签名（使用此批注的位置），否则编译器将抛出编译错误。如果您没有使用此注解，则很难跟踪。

例：

```java
public class MyParentClass {

    public void justaMethod() {
        System.out.println("Parent class method");
    }
}

public class MyChildClass extends MyParentClass {

    @Override
    public void justaMethod() {
        System.out.println("Child class method");
    }
}
```

我相信这个例子是自我解释的。要阅读有关此注解的更多信息，请参阅以下文章： [`@Override内置注解](https://beginnersbook.com/2014/07/override-annotation-in-java/)。

#### 2）`@Deprecated`

`@Deprecated`注解表示已弃用标记的元素（类，方法或字段），不应再使用。只要程序使用已经使用`@Deprecated`注解标记的方法，类或字段，编译器就会生成警告。不推荐使用元素时，也应使用 Javadoc `@deprecated`标记对其进行记录，如以下示例所示。记下`@Deprecated`和`@deprecated`的大小写差异。`@deprecated`用于文档目的。

示例：

```java
/**
 * @deprecated
 * reason for why it was deprecated
 */
@Deprecated
public void anyMethodHere(){
    // Do something
}
```

现在，只要任何程序使用此方法，编译器就会生成警告。要阅读有关此注解的更多信息，请参阅以下文章： [Java - `@Deprecated`注解](https://beginnersbook.com/2014/07/deprecated-annotation-in-java/) 。

#### 3）`@SuppressWarnings`

此批注指示编译器忽略特定警告。例如，在下面的代码中，我调用了一个不推荐使用的方法（假设方法`deprecatedMethod()`标有`@Deprecated`注解），因此编译器应该生成警告，但是我使用`@SuppressWarnings`注解来抑制弃用警告。

```java
@SuppressWarnings("deprecation")
    void myMethod() {
        myObject.deprecatedMethod();
}
```

## 创建自定义注解

*   注解是使用`@interface`创建的，后跟注解名称，如下例所示。
*   注解也可以包含元素。他们看起来像方法。例如，在下面的代码中，我们有四个元素。我们不应该为这些元素提供实现。
*   所有注解都扩展了`java.lang.annotation.Annotation`接口。注解不能包含任何`extends`子句。

```java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation{
    int studentAge() default 18;
    String studentName();
    String stuAddress();
    String stuStream() default "CSE";
}
```

注意：使用注解时，可以跳过在创建注解时设置了默认值的所有元素。例如，如果我将上述注解应用于类，那么我会这样做：

```java
@MyCustomAnnotation(
    studentName="Chaitanya",
    stuAddress="Agra, India"
)
public class MyClass {
...
}
```

如您所见，我们没有给`studentAge`和`stuStream`元素赋予任何值，因为设置这些元素的值是可选的（默认值已经在注解定义中设置，但是如果您希望可以分配新的使用注解时的值与我们对其他元素的处理方式相同）。但是，我们必须在使用注解时提供其他元素的值（没有设置默认值的元素）。

**注意**：我们也可以在注解中包含数组元素。这就是我们如何使用它们：
注解定义：

```java
@interface MyCustomAnnotation {
    int      count();
    String[] books();
}
```

用法：

```java
@MyCustomAnnotation(
    count=3,
    books={"C++", "Java"}
)
public class MyClass {

}
```

再次回到主题：在自定义注解示例中，我们使用了这四个注解：`@Documented`，`@Target`，`@Inherited`和`@Retention`。让我们详细讨论它们。

#### `@Documented`

`@Documented`注解表明使用此注解的元素应由 JavaDoc 记录。例如：

```java
java.lang.annotation.Documented
@Documented
public @interface MyCustomAnnotation {
  //Annotation body
}
```

```java
@MyCustomAnnotation
public class MyClass { 
     //Class body
}
```

在为类`MyClass`生成 javadoc 时，注解`@MyCustomAnnotation`将包含在其中。

#### `@Target`

它指定了我们可以使用注解的位置。例如：在下面的代码中，我们将目标类型定义为`METHOD`，这意味着下面的注解只能用于方法。

```java
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
public @interface MyCustomAnnotation {

}
```

```java
public class MyClass {
   @MyCustomAnnotation
   public void myMethod()
   {
       //Doing something
   }
}
```

**注意**：1）如果您没有定义任何目标类型，则意味着可以将注解应用于任何元素。

2）除了`ElementType.METHOD`之外，注解可以具有以下可能的`Target`值。

```java
ElementType.METHOD
ElementType.PACKAGE
ElementType.PARAMETER
ElementType.TYPE
ElementType.ANNOTATION_TYPE
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.FIELD
```

#### `@Inherited`

`@Inherited`注解表示类中使用的自定义注解应该由其所有子类继承。例如：

```java
java.lang.annotation.Inherited

@Inherited
public @interface MyCustomAnnotation {

}
```

```java
@MyCustomAnnotation
public class MyParentClass { 
  ... 
}
```

```java
public class MyChildClass extends MyParentClass { 
   ... 
}
```

这里的类`MyParentClass`正在使用注解`@MyCustomAnnotation`，该注解用`@inherited`注解标记。这意味着子类`MyChildClass`继承了`@MyCustomAnnotation`。

#### `@Retention`

它指示要保留带注解类型的注解的时间长度。

```java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MyCustomAnnotation {

}
```

这里我们使用了`RetentionPolicy.RUNTIME`。还有另外两种选择。让我们看看他们的意思：
`RetentionPolicy.RUNTIME`：注解应该在运行时可用，以便通过 java 反射进行检查。
`RetentionPolicy.CLASS`：注解将在`.class`文件中，但在运行时不可用。
`RetentionPolicy.SOURCE`：注解将在程序的源代码中提供，它既不在`.class`文件中，也不在运行时可用。

这就是“Java 注解”这个主题的全部内容。如果您有任何疑问，请随时在下面留言。