Java 注解学习笔记

 更新时间:2021年03月02日 10:37:13   作者:布禾  
这篇文章主要介绍了Java 注解的相关资料,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下

简介

Java注解是JDK1.5引入的一种注释机制,它不会改变编译器的编译方式,Java编译器对包含注解和不包含注解的代码会生成相同的Java虚拟机指令。在实际应用中,注解只是一种标识,具体的操作需要借助其他工具来解析和处理。

注解语法

注解是使用@interface来定义的,所有注解都隐式的扩展自java.lang.annotation.Annotation接口。

如下MyFirstAnnotation是一个自定义注解,它具有两个参数name和value,默认值都为空字符串。在它的定义之上还标注了@Retention和@Target两个元注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotation {
  String name() default "";

  String value() default "";
}

注解参数类型是有限制的,必须限制在以下几种类型中:

  1. 基本类型
  2. String
  3. Class
  4. enum类型
  5. 注解类型
  6. 由前面所述类型组成的数组

例如,如果不使用以上几种,则会出现编译错误:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotation {
  String name() default "";

  Integer value() default 1;//包装类型也不行,编译错误
}

@Target和@Retention这种作用在注解上的注解,称之为元注解。常用的元注解如下:

1.@Target,用于标识注解可以标注的位置,接收一个ElementType[]参数。参数取值可以参考ElementType枚举类:

public enum ElementType {
  /** 类、接口(包括注释类型)或枚举声明 */
  TYPE,

  /** 字段声明(包括enum常量) */
  FIELD,

  /** 方法声明 */
  METHOD,

  /** 形参声明 */
  PARAMETER,

  /** 构造函数声明 */
  CONSTRUCTOR,

  /** 局部变量声明 */
  LOCAL_VARIABLE,

  /** 注解类型声明 */
  ANNOTATION_TYPE,

  /** 包声明 */
  PACKAGE,

  /**
   * 类型参数声明
   *
   * @since 1.8
   */
  TYPE_PARAMETER,

  /**
   * 任何类型名称
   *
   * @since 1.8
   */
  TYPE_USE
}

当指定的@Target和注解的使用位置不匹配时就会出现编译错误,如下所示,@Target(ElementType.METHOD)表示MyFirstAnnotation注解只能用来标注方法,标注在类上就出现编译错误:

//编译错误
@MyFirstAnnotation
public class Demo {

  //正确
  @MyFirstAnnotation
  public void doSomeThing(){
  }

}

2.@Retention,用于标识注解可以保留多久,接收一个RetentionPolicy参数,参数取值可以参考RetentionPolicy枚举类:

public enum RetentionPolicy {
  /**
   * 表示注解只会存在于.java的源代码文件中,不会保留到编译后的.class文件中
   */
  SOURCE,

  /**
   * 表示注解可以保留到.class文件中,但是不会被Java虚拟机所加载
   */
  CLASS,

  /**
   * 表示注解可以保留到.class文件中,并由虚拟机加载
   */
  RUNTIME
}

3.@Documented,表示这个注解能出现在javadoc中。

4.@Inherited,表示当这个注解用于一个类的时候,能够自动的被它的子类继承。

5.@Repeatable,表示这个注解可以在同一个位置应用多次。

默认情况下,同一个位置添加多个重复注解会有编译错误:

public class Demo {
  //编译错误
  @MyFirstAnnotation(name = "张三")
  @MyFirstAnnotation(name = "李四")
  @MyFirstAnnotation(name = "王五")
  public void doSomeThing(){
  }

}

可以通过添加@Repeatable元注解来使@MyFirstAnnotation能重复使用。
首先需要创建一个容器注解@MyFirstAnnotations,容器注解@MyFirstAnnotations必须要有一个参数value,并且其类型为MyFirstAnnotation[]:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotations {
  MyFirstAnnotation[] value();
}

然后添加@Repeatable注解,并指定容器注解。

@Repeatable(MyFirstAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotation {
  String name() default "";

  String value() default "";
}

关于注解的使用需要注意,注解参数是不能为null的,默认值也是不能为null。

自定义注解测试

定义注解@RepeatMethod,包含int类型参数value。

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.RUNTIME)
public @interface RepeatMethod {

  int value() default 1;

}

在doSomeThing方法上应用注解。如果要指定的注解参数为value,并且没有指定其他的参数值时,可以采用简写的方式,省略参数名和等号。

public class Demo {
  @RepeatMethod(5)
  public void doSomeThing(){
    System.out.println("----注解测试----");
  }
}

通过反射获取注解信息,然后做对应的处理,如假设@RepeatMethod注解的作用是重复调用被标注的方法,参数value是指定重复调用方法的次数:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyDemo {
  public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
    Class cla = Demo.class;
    Method[] methods = cla.getMethods();
    Object demo = cla.newInstance();
    for (Method method : methods){
      //判断方法上是否有标注@RepeatMethod注解
      if(method.isAnnotationPresent(RepeatMethod.class)){
        //获取RepeatMethod注解的参数值
        RepeatMethod repeatMethod = method.getAnnotation(RepeatMethod.class);
        for (int i = 0;i < repeatMethod.value(); i++)
        method.invoke(demo, null);
      }
    }
  }
}

输出结果:

----注解测试----
----注解测试----
----注解测试----
----注解测试----
----注解测试----

以上就是Java 注解学习笔记的详细内容,更多关于Java 注解的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈Java类的加载,链接及初始化

    浅谈Java类的加载,链接及初始化

    今天给大家带来的是关于Java的相关知识,文章围绕着Java类的加载,链接及初始化展开,文中有非常详细的解释及代码示例,需要的朋友可以参考下
    2021-06-06
  • java 开发中网络编程之IP、URL详解及实例代码

    java 开发中网络编程之IP、URL详解及实例代码

    这篇文章主要介绍了java 开发中网络编程之IP、URL详解及实例代码的相关资料,需要的朋友可以参考下
    2017-03-03
  • System 类 和 Runtime 类的常用用法介绍

    System 类 和 Runtime 类的常用用法介绍

    这篇文章主要介绍了System 类 和 Runtime 类的常用用法,有需要的朋友可以参考一下
    2014-01-01
  • @PathVariable为空时指定默认值的操作

    @PathVariable为空时指定默认值的操作

    这篇文章主要介绍了@PathVariable为空时指定默认值的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • RHEL6.5下JDK1.8安装教程

    RHEL6.5下JDK1.8安装教程

    这篇文章主要为大家详细介绍了RHEL6.5下JDK1.8安装教程的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • SpringBoot disruptor高性能队列使用

    SpringBoot disruptor高性能队列使用

    这篇文章主要介绍了SpringBoot disruptor高性能队列使用,Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题
    2023-02-02
  • Java并发工具类LongAdder原理实例解析

    Java并发工具类LongAdder原理实例解析

    这篇文章主要介绍了Java并发工具类LongAdder原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • 浅谈Java到底是值传递还是引用传递呢

    浅谈Java到底是值传递还是引用传递呢

    今天带大家学习Java的相关知识,文章围绕着Java到底是值传递还是引用传递展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Mybatis利用分页插件PageHelper快速实现分页查询

    Mybatis利用分页插件PageHelper快速实现分页查询

    如果你也在用MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件,这篇文章主要给大家介绍了关于Mybatis利用分页插件PageHelper快速实现分页查询的相关资料,PageHelper是一个Mybatis的分页插件,负责将已经写好的sql语句,进行分页加工,需要的朋友可以参考下
    2021-08-08
  • MyBatis传递多个参数方式

    MyBatis传递多个参数方式

    这篇文章主要介绍了MyBatis传递多个参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02

最新评论