# Java 注解类型

> 原文： [https://www.programiz.com/java-programming/annotation-types](https://www.programiz.com/java-programming/annotation-types)

#### 在本教程中，我们将借助示例学习不同类型的 Java 注解。

Java 注解是程序源代码的元数据（有关数据的数据）。 Java SE 提供了几个预定义的注解。 此外，我们还可以根据需要创建自定义注解。

如果您不知道什么是注解，请访问 [Java 注解](/java-programming/annotations "Java Annotations")教程。

这些注解可以分类为：

1\. **预定义的注解**

*   `@Deprecated`
*   `@Override`
*   `@SuppressWarnings`
*   `@SafeVarargs`
*   `@FunctionalInterface`

2\. **自定义注解**

3\. **元注解**

*   `@Retention`
*   `@Documented`
*   `@Target`
*   `@Inherited`
*   `@Repeatable`

* * *

## 预定义的注解类型

### 1\. `@Deprecated`

`@Deprecated`注解是标记注解，指示不赞成使用元素（类，方法，字段等），并已用较新的元素替换。

其语法为：

```java
@Deprecated
accessModifier returnType deprecatedMethodName() { ... } 
```

当程序使用已声明为已弃用的元素时，编译器将生成警告。

我们使用 Javadoc `@deprecated`标记来记录已弃用的元素。

```java
/**
 * @deprecated
 * why it was deprecated
 */
@Deprecated
accessModifier returnType deprecatedMethodName() { ... } 
```

### 示例 1：`@Deprecated`注解示例

```java
class Main {
  /**
   * @deprecated
   * This method is deprecated and has been replaced by newMethod()
   */
  @Deprecated
  public static void deprecatedMethod() { 
    System.out.println("Deprecated method"); 
  } 

  public static void main(String args[]) {
    deprecatedMethod();
  }
} 
```

**输出**

```java
Deprecated method 
```

* * *

### 2\. @Override

`@Override`注解指定子类的方法使用相同的方法名称，返回类型和参数列表覆盖超类的方法。

覆盖方法时，并非必须使用`@Override`。 但是，如果使用它，则在覆盖该方法时，如果出现错误（例如错误的参数类型），则编译器将给出错误。

### 示例 2：`@Override`注解示例

```java
class Animal {

  // overridden method
  public void display(){
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // overriding method
  @Override
  public void display(){
    System.out.println("I am a dog");
  }

  public void printMessage(){
    display();
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printMessage();
  }
} 
```

**输出**

```java
I am a dog 
```

在此示例中，通过使`Dog`类的对象`dog1`，我们可以调用其方法`printMessage()`，该方法然后执行`display()`语句。

由于在两个类中都定义了`display()`，因此`Dog`子类的方法将覆盖`Animal`超类的方法。 因此，将调用子类的`display()`。

* * *

### 3\. @SuppressWarnings

顾名思义，`@SuppressWarnings`注解指示编译器禁止在程序执行时生成警告。

我们可以指定要取消的警告类型。 可以禁止的警告是特定于编译器的，但有两类警告：**弃用**和**未选中**。

为了禁止显示特定类别的警告，我们使用：

```java
@SuppressWarnings("warningCategory") 
```

例如，

```java
@SuppressWarnings("deprecated") 
```

为了禁止显示多类警告，我们使用：

```java
@SuppressWarnings({"warningCategory1", "warningCategory2"}) 
```

例如：

```java
@SuppressWarnings({"deprecated", "unchecked"}) 
```

类别`deprecated`指示编译器在使用不推荐使用的元素时禁止显示警告。

类别`unchecked`指示编译器在使用原始类型时禁止显示警告。

并且，未定义的警告将被忽略。 例如，

```java
@SuppressWarnings("someundefinedwarning") 
```

### 示例 3：`@SuppressWarnings`注解示例

```java
class Main {
  @Deprecated
  public static void deprecatedMethod() { 
    System.out.println("Deprecated method"); 
  } 

  @SuppressWarnings("deprecated")
  public static void main(String args[]) {
    Main depObj = new Main();
    depObj. deprecatedMethod();
  }
} 
```

**输出**：

```java
Deprecated method 
```

在这里，`deprecatedMethod()`已被标记为已弃用，并且在使用时会发出编译器警告。 通过使用`@SuppressWarnings("deprecated")`注解，我们可以避免编译器警告。

* * *

### 4\. `@SafeVarargs`

`@SafeVarargs`注解断言，带注解的方法或构造器不会对其可变参数（可变数量的参数）执行不安全的操作。

我们只能在不能被覆盖的方法或构造器上使用此注解。 这是因为覆盖它们的方法可能执行不安全的操作。

在 Java 9 之前，我们只能在`final`或`static`方法上使用此注解，因为它们不能被覆盖。 现在，我们也可以将此注解用于私有方法。

### 示例 4：`@SafeVarargs`注解示例

```java
import java.util.*;

class Main {

  private void displayList(List<String>... lists) {
    for (List<String> list : lists) {
      System.out.println(list);
    }
  }

  public static void main(String args[]) {
    Main obj = new Main();

    List<String> universityList = Arrays.asList("Tribhuvan University", "Kathmandu University");
    obj.displayList(universityList);

    List<String> programmingLanguages = Arrays.asList("Java", "C");
    obj.displayList(universityList, programmingLanguages);
  }
} 
```

**警告**

```java
Type safety: Potential heap pollution via varargs parameter lists
Type safety: A generic array of List<String> is created for a varargs 
 parameter 
```

**输出**：

```java
Note: Main.java uses unchecked or unsafe operations.
[Tribhuvan University, Kathmandu University]
[Tribhuvan University, Kathmandu University]
[Java, C] 
```

在这里，`List ... lists`指定类型为`List`的变长参数。 这意味着方法`displayList()`可以具有零个或多个参数。

上面的程序编译没有错误，但是当不使用`@SafeVarargs`注解时会发出警告。

在上面的示例中使用`@SafeVarargs`注解时，

```java
@SafeVarargs
 private void displayList(List<String>... lists) { ... }

```

我们得到相同的输出，但没有任何警告。 当使用此注解时，非受检的警告也会被删除。

* * *

### 5\. @FunctionalInterface

Java 8 首先引入了此`@FunctionalInterface`注解。 该注解指示使用它的类型声明是一个函数式接口。 一个函数式接口只能有一个抽象方法。

### 示例 5：`@FunctionalInterface`注解示例

```java
@FunctionalInterface
public interface MyFuncInterface{
  public void firstMethod(); // this is an abstract method
} 
```

如果我们添加另一个抽象方法，那么说

```java
@FunctionalInterface
public interface MyFuncInterface{
  public void firstMethod(); // this is an abstract method
  public void secondMethod(); // this throws compile error
} 
```

现在，当我们运行程序时，我们将收到以下警告：

```java
Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ MyFuncInterface is not a functional interface
multiple non-overriding abstract methods found in interface MyFuncInterface 
```

使用`@FunctionalInterface`注解不是强制性的。 编译器会将满足函数式接口定义的任何接口视为函数式接口。

我们使用此注解来确保函数式接口只有一种抽象方法。

但是，由于它们具有实现，因此可以具有任意数量的默认方法和静态方法。

```java
@FunctionalInterface
public interface MyFuncInterface{
  public void firstMethod(); // this is an abstract method
  default void secondMethod() { ... } 
  default void thirdMethod() { ... } 
} 
```

* * *

## 自定义注解

也可以创建我们自己的自定义注解。

它的语法是：

```java
[Access Specifier] @interface<AnnotationName> {         
  DataType <Method Name>() [default value];
}

```

这是您需要了解的有关自定义注解的信息：

*   可以通过使用`@interface`和注解名称来创建注解。
*   注解可以具有看起来像方法的元素，但是它们没有实现。
*   默认值是可选的。 参数不能为空值。
*   方法的返回类型可以是原始，枚举，字符串，类名或这些类型的数组。

### 示例 6：自定义注解示例

```java
@interface MyCustomAnnotation {
  String value() default "default value";
}

class Main {
  @MyCustomAnnotation(value = "programiz")
  public void method1() {
    System.out.println("Test method 1");
  }

  public static void main(String[] args) throws Exception {
    Main obj = new Main();
    obj.method1();
  }
} 
```

**输出**：

```java
Test method 1 
```

* * *

## 元注解

元注解是应用于其他注解的注解。

### 1\. `@Retention`

`@Retention`注解指定注解可以使用的级别。

它的语法是：

```java
@Retention(RetentionPolicy) 
```

保留策略有 3 种类型：

*   **`RetentionPolicy.SOURCE`** - 注解仅在源级别可用，并且被编译器忽略。
*   **`RetentionPolicy.CLASS`** - 注解在编译时可供编译器使用，但被 Java 虚拟机（JVM）忽略。
*   **`RetentionPolicy.RUNTIME`** - 注解可用于 JVM。

例如：

```java
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation{ ... } 
```

* * *

### 2\. `@Documented`

默认情况下，自定义注解不包含在[官方 Java 文档](https://www.oracle.com/technetwork/articles/java/index-137868.html)中。 为了将注解包含在 Javadoc 文档中，我们使用`@Documented`注解。

例如：

```java
@Documented
public @interface MyCustomAnnotation{ ... } 
```

* * *

### 3\. `@Target`

我们可以使用`@Target`注解将注解限制为应用于特定目标。

它的语法是：

```java
@Target(ElementType) 
```

`ElementType`可以具有以下类型之一：

| 元素类型 | 目标 |
| --- | --- |
| `ElementType.ANNOTATION_TYPE` | 注解类型 |
| `ElementType.CONSTRUCTOR` | 构造器 |
| `ElementType.FIELD` | 字段 |
| `ElementType.LOCAL_VARIABLE` | 局部变量 |
| `ElementType.METHOD` | 方法 |
| `ElementType.PACKAGE` | 包 |
| `ElementType.PARAMETER` | 参数 |
| `ElementType.TYPE` | 任何类元素 |

例如：

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

在此示例中，我们仅将此注解的使用限制为方法。

**注意**：如果未定义目标类型，则注解可用于任何元素。

* * *

### 4\. `@Inherited`

默认情况下，注解类型不能从超类继承。 但是，如果需要将注解从超类继承到子类，则可以使用`@Inherited`注解。

它的语法是：

```java
@Inherited 
```

例如：

```java
@Inherited
public @interface MyCustomAnnotation { ... }

@MyCustomAnnotation
public class ParentClass{ ... }

public class ChildClass extends ParentClass { ... } 
```

* * *

### 5\. `@Repeatable`

由`@Repeatable`标记的注解可以多次应用于同一声明。

```java
@Repeatable(Universities.class)
public @interface University {
  String name();
} 
```

`@Repeatable`注解中定义的值是容器注解。 容器注解具有上述可重复注解的数组类型的变量`value`。 在此，`Universities`是包含注解的类型。

```java
public @interface Universities {
  University[] value();
} 
```

现在，`@University`注解可以在同一声明中多次使用。

```java
@University(name = "TU")
@University(name = "KU")
private String uniName; 
```

* * *

如果需要检索注解数据，则可以使用 [Reflection API](/java-programming/reflection "Java Reflection") 。

要检索注解值，我们使用在反射 API 中定义的`getAnnotationsByType()`或`getAnnotations()`方法。