💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 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()`方法。