Java进阶之标准注解

简介: 【7月更文挑战第15天】Java标准注解包括标记注解(如@Deprecated)、@Override(检查方法重写)、@SuppressWarnings(抑制警告)。多值注解如@RequestMapping在Spring中用于HTTP请求映射。元注解如@Retention控制注解保留策略,@Target指定应用位置。Java8引入类型注解(@FunctionalInterface、@SafeVarargs)和重复注解(@Repeatable)。自定义注解可通过反射读取,如示例中的MyMarkerAnnotation等。

Java进阶之标准注解
Java内置的注解是JDK中自带的注解,也叫Java标准注解,注解其实是一种标记,用来做一个标识。
比如上面学过的函数式接口,就是通过@FunctionalInterface来标识这个接口是函数式接口,即接口中只有一个抽象方法的接口。
Java中的标准注解(内置注解)主要分为以下几类:
标记注解(Marker Annotations): 这类注解不包含任何元素,也就是说,它们没有参数。它们的存在仅仅是为了标记某个程序元素。例如,@Deprecated 就是一个标记注解,用来标记过时的元素。
@Override:表示当前的方法是重写父类的方法。这个很常见。
// @Override示例
class Parent {
void someMethod() {
// do something
}
}
class Child extends Parent {
@Override // 表示这个方法覆盖了父类的someMethod方法
void someMethod() {
// do something
}
}
@Deprecated:表示某个元素(类、方法等)已经过时,不建议使用。
// @Deprecated示例
class Example {
@Deprecated // 表示这个方法不再推荐使用
void deprecatedMethod() {
// do something
}
}
如果被@Deprecated标识了,那么在调用的时候,方法名上就会显示删除线。
单值注解(Single-Value Annotations): 这类注解包含一个名为 “value” 的元素。在使用时,你可以直接指定该元素的值,而不需要明确写出 “value=”。例如,@SuppressWarnings 通常只设置一个值来指定要抑制的警告类型。
@SuppressWarnings:告诉编译器忽略特定的警告。
// @SuppressWarnings示例
class WarningExample {
@SuppressWarnings("unchecked") // 告诉编译器忽略未检查的转换警告
void ignoreWarnings() {
List list = new ArrayList();
}
}
@SuppressWarnings 注解可以应用于类、方法或者变量声明。它可以接受一个字符串数组作为参数,每个字符串代表一个警告类型。例如:
deprecation:使用了已过时的 API。
unchecked:执行了未经检查的类型转换。
rawtypes:使用了原始类型的泛型。
serial:可序列化的类缺少 serialVersionUID 字段。
finally:finally 子句无法正常完成。
all:抑制所有警告。
也可以同时声明两个类型:@SuppressWarnings("unchecked","deprecation")
警告最好尽可能地解决,而不是简单地使用@SuppressWarnings抑制它们。
多值注解(Multi-Value Annotations): 这类注解包含多个元素,每个元素都可以设置一个值。在使用时,你需要为每个元素指定值。例如,@RequestMapping 在 Spring 框架中用于映射 HTTP 请求到控制器的处理方法,它包含多个元素如 “path”, “method” 等。
元注解(Meta-Annotations): 这类注解用于注解其他注解。元注解定义了其他注解的行为和特性,用于定义和约束其他注解的类型和用法。
元注解用来自定义注解,以指定注解的行为、适用范围、保留策略等。
@Retention:指定被它注解的注解的保留策略,标识这个注解怎么保留。
它有一个RetentionPolicy类型的参数,这个参数有三个可选的策略值:
RetentionPolicy.SOURCE:注解只保留在源代码层面,在编译期间就会被忽略。SOURCE(只在源码中保留)
RetentionPolicy.CLASS:注解会被保留到编译后的字节码文件中,但在运行时环境中不会被虚拟机读取。CLASS(在字节码中保留)
RetentionPolicy.RUNTIME:注解会被保留到运行时环境中,可以通过反射机制读取注解信息。RUNTIME(在运行时保留)
下面是一个使用 @Retention 注解的示例:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

  // 指定 MyAnnotation 注解的保留策略为运行时
  @Retention(RetentionPolicy.RUNTIME)
  public @interface MyAnnotation {
      String value() default "default value";
  }
  在这个示例中,我们定义了一个名为 MyAnnotation 的自定义注解,并使用 @Retention(RetentionPolicy.RUNTIME) 来指定这个注解在运行时是可见的。

  @Target:用于标识指定被它注解的注解可以应用于哪些程序元素,哪些地方,如类型、方法、字段等。
  它有一个ElementType类型的参数,这个参数有多个可选的值,如:
  ElementType.TYPE:类、接口(包括注解类型)或枚举声明。
  ElementType.FIELD:字段声明(包括枚举常量)。
  ElementType.METHOD:方法声明。
  ElementType.PARAMETER:参数声明。
  ElementType.CONSTRUCTOR:构造函数声明。
  ElementType.LOCAL_VARIABLE:局部变量声明。
  ElementType.ANNOTATION_TYPE:注解类型声明。
  ElementType.PACKAGE:包声明。
  ElementType.TYPE_PARAMETER(Java 8+):类型参数声明。
  ElementType.TYPE_USE(Java 8+):类型使用声明。
  示例:
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Target;

  // 指定 MyAnnotation 注解可以应用于方法声明
  @Target(ElementType.METHOD)
  public @interface MyAnnotation {
      String value() default "default value";
  }
  在这个示例中,我们定义了一个名为MyAnnotation的自定义注解,并使用@Target(ElementType.METHOD)来指定这个注解只能应用于方法声明,不能应用于类、字段或其他程序元素,否则会编译错误。
  @Documented注解是一个标记注解,用于指示被它注解的注解应该被包含在 Javadoc 生成的文档中。当一个注解被 @Documented 注解时,如果使用了这个注解的元素被 Javadoc 工具处理,那么这个注解的信息将会出现在生成的文档中。@Documented专门用来修饰其他注解类型(元注解),它不能直接应用于类、方法或字段等程序元素。
  @Inherited:用于指定被它注解的注解将具有继承性。如果一个类使用了被@Inherited注解的注解,那么它的子类也会自动继承这个注解。当一个注解被 @Inherited 注解时,如果某个类使用了这个注解,那么它的子类将自动继承这个注解,除非子类明确地使用了相同的注解但有不同的值。

  Java8中引入了类型注解和重复注解,扩展了 Java 注解的功能。
  类型注解(Type Annotations): 这类注解是Java8引入的,它们可以应用于任何类型的使用,而不仅仅是声明。
  Java 8 引入的类型注解包括:
  @FunctionalInterface:标记一个接口是一个函数式接口,它必须包含一个抽象方法。这个我们前面函数式编程的时候说过,标记是只有一个抽象方法的接口为函数式接口,不标记编译器也会自己判断。
  @SafeVarargs:这个应该是Java7引入的,标记一个方法,表明它对使用可变参数作为泛型类型参数是安全的。就是说我们使用泛型作为可变参数的时候,表明我们已经确保它是不会出现非法类型的,用来消除类型不安全警告。
  示例:
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;

  // 定义一个注解,用于标记一个方法是安全的可变参数泛型方法
  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.SOURCE)
  public @interface SafeVarargsMethod {
  }

  public class SafeVarargsExample {

      // 定义一个方法,使用可变参数作为泛型类型参数
      @SafeVarargsMethod
      public <T> void safeVarargsMethod(List<T> list, T... args) {
          // 方法实现,假设 args 永远不会包含非 T 类型的元素
          for (T arg : args) {
              list.add(arg);
          }
      }
  }

  也可以自定义类型注解@NonNull,可以用于指示一个变量或参数不应该为null。这种一般三方类库中会提供。
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;

  // 定义一个注解,用于指示一个参数不应该为 null
  @Target(ElementType.PARAMETER)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface NonNull {
  }
  public class NonNullExample {
      // 方法接受一个带有 @NonNull 注解的参数
      public void exampleMethod(@NonNull String parameter) {
          // 方法实现,假设 parameter 永远不为 null
      }
  }
  在 NonNullExample 类的 exampleMethod 方法上,我们使用 @NonNull 注解来标记参数 parameter。这意味着 parameter 在调用这个方法时不应该为 null。
  通过使用@NonNull,我们可以强制方法参数在运行时不为null,从而提高代码的健壮性和可维护性。如果尝试传递一个null值给标记了@NonNull的参数,编译器将会报错,或者在运行时抛出异常。



  重复注解(Repeatable Annotations): 这类注解是Java8引入的,它们允许在同一位置多次使用相同的注解。为了实现这一点,需要定义一个容器注解来保存重复注解的数组。例如,@Repeatable 元注解用于指示一个注解是可以重复的。
  @Repeatable:Java8引入,允许一个注解在同一声明或类型上多次使用。
  在Java8之前,如果需要在同一个元素上使用多个相同的注解,需要使用注解数组或创建多个不同的注解。java8引入了@Repeatable可以在添加多个相同的注解时,每个注解都有不同的配置或参数。
  它允许在同一声明或类型上多次使用同一个注解。为了使一个注解可重复,需要定义一个容器注解,用于保存重复注解的数组。
  下面是一个使用 @Repeatable 注解的示例:
  import java.lang.annotation.Repeatable;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;

  // 定义一个可重复的注解
  @Repeatable(MyRepeatableAnnotations.class)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface MyRepeatableAnnotation {
      String value();
  }
  // 定义一个容器注解,用于保存 MyRepeatableAnnotation 的数组
  @Retention(RetentionPolicy.RUNTIME)
  public @interface MyRepeatableAnnotations {
      MyRepeatableAnnotation[] value();
  }
  // 使用 @RepeatableAnnotation 的示例
  public class RepeatableExample {
      // 在同一个方法上多次使用 @MyRepeatableAnnotation
      @MyRepeatableAnnotation("First annotation")
      @MyRepeatableAnnotation("Second annotation")
      public void myMethod() {
          // 方法实现
      }
  }
  在这个示例中,我们定义了一个名为 MyRepeatableAnnotation 的可重复注解,并使用 @Repeatable 来指定它的容器注解为 MyRepeatableAnnotations。我们还定义了 MyRepeatableAnnotations 容器注解,它包含一个 MyRepeatableAnnotation 类型的数组。
  然后,在 RepeatableExample 类的 myMethod 方法上,我们多次使用了 @MyRepeatableAnnotation 注解,每个注解都有不同的值。

  自定义一个注解示例:
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Repeatable;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;
  import java.lang.reflect.Method;

  public class AnnotationExample {
      // 定义一个标记注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      public @interface MyMarkerAnnotation {
      }
      // 定义一个单值注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      public @interface MySingleValueAnnotation {
          String value();
      }
      // 定义一个多值注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      public @interface MyMultiValueAnnotation {
          String name();
          int age();
      }
      // 定义一个可重复的注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      @Repeatable(MyRepeatableAnnotations.class)
      public @interface MyRepeatableAnnotation {
          String value();
      }
      // 定义一个容器注解来保存可重复注解的数组
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      public @interface MyRepeatableAnnotations {
          MyRepeatableAnnotation[] value();
      }

      // 使用自定义注解的方法
      @MyMarkerAnnotation
      @MySingleValueAnnotation("Single value")
      @MyMultiValueAnnotation(name = "Multi", age = 25)
      @MyRepeatableAnnotation("First repeatable")
      @MyRepeatableAnnotation("Second repeatable")
      public void annotatedMethod() {
          // 方法实现
      }
      public static void main(String[] args) {
          try {
              // 获取 AnnotationExample 类的 Class 对象
              Class<?> clazz = AnnotationExample.class;
              // 获取名为 "annotatedMethod" 的方法
              Method method = clazz.getMethod("annotatedMethod");
              // 获取并打印标记注解
              MyMarkerAnnotation markerAnnotation = method.getAnnotation(MyMarkerAnnotation.class);
              System.out.println("Marker Annotation: " + markerAnnotation);
              // 获取并打印单值注解
              MySingleValueAnnotation singleValueAnnotation = method.getAnnotation(MySingleValueAnnotation.class);
              System.out.println("Single Value Annotation: " + singleValueAnnotation.value());
              // 获取并打印多值注解
              MyMultiValueAnnotation multiValueAnnotation = method.getAnnotation(MyMultiValueAnnotation.class);
              System.out.println("Multi Value Annotation - Name: " + multiValueAnnotation.name());
              System.out.println("Multi Value Annotation - Age: " + multiValueAnnotation.age());
              // 获取并打印可重复注解
              MyRepeatableAnnotation[] repeatableAnnotations = method.getAnnotationsByType(MyRepeatableAnnotation.class);
              System.out.println("Repeatable Annotations:");
              for (MyRepeatableAnnotation repeatableAnnotation : repeatableAnnotations) {
                  System.out.println(repeatableAnnotation.value());
              }
          } catch (NoSuchMethodException e) {
              e.printStackTrace();
          }
      }
  }
  在这个示例中,我们定义了四个注解:一个标记注解、一个单值注解、一个多值注解和一个可重复的注解。然后,我们在 annotatedMethod 方法上使用了这些注解。在 main 方法中,我们使用反射来获取 annotatedMethod 方法的注解信息,并打印出来。
  END
目录
相关文章
|
28天前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
86 43
Java学习十六—掌握注解:让编程更简单
|
23天前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
44 14
|
23天前
|
前端开发 Java
[Java]讲解@CallerSensitive注解
本文介绍了 `@CallerSensitive` 注解及其作用,通过 `Reflection.getCallerClass()` 方法返回调用方的 Class 对象。文章还详细解释了如何通过配置 VM Options 使自定义类被启动类加载器加载,以识别该注解。涉及的 VM Options 包括 `-Xbootclasspath`、`-Xbootclasspath/a` 和 `-Xbootclasspath/p`。最后,推荐了几篇关于 ClassLoader 的详细文章,供读者进一步学习。
29 12
|
16天前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
28 0
|
1月前
|
JSON Java 数据库
java 常用注解大全、注解笔记
关于Java常用注解的大全和笔记,涵盖了实体类、JSON处理、HTTP请求映射等多个方面的注解使用。
35 0
java 常用注解大全、注解笔记
|
2月前
|
Arthas Java 测试技术
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
Java字节码文件、组成、详解、分析;常用工具,jclasslib插件、阿里arthas工具;如何定位线上问题;Java注解
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
|
1月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
16 0
|
2月前
|
Java 编译器 程序员
Java注解,元注解,自定义注解的使用
本文讲解了Java中注解的概念和作用,包括基本注解的用法(@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface),Java提供的元注解(@Retention, @Target, @Documented, @Inherited),以及如何自定义注解并通过反射获取注解信息。
Java注解,元注解,自定义注解的使用
|
1月前
|
XML Java 数据格式
Java-spring注解的作用
Java-spring注解的作用
23 0
|
2月前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit