Java 注解学习笔记

作者:布禾 时间:2022-12-25 02:40:54 

简介

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);
     }
   }
 }
}

输出结果:


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

来源:https://www.cnblogs.com/seve/p/14441203.html

标签:Java,注解
0
投稿

猜你喜欢

  • Kotlin协程launch启动流程原理详解

    2021-10-31 15:47:22
  • 详解SpringBoot启动代码和自动装配源码分析

    2021-10-18 08:49:21
  • SpringBoot新手入门的快速教程

    2021-09-28 23:23:25
  • c# wpf如何附加依赖项属性

    2023-01-09 05:05:56
  • Java集合Stream流操作的基本使用教程分享

    2023-09-01 01:05:03
  • 基于Android AIDL进程间通信接口使用介绍

    2021-12-28 05:15:22
  • Java设计模式七大原则之单一职责原则详解

    2022-05-12 20:48:58
  • Java通过CMD方式读取注册表任意键值对代码实践

    2021-10-10 19:56:40
  • Spring Boot项目如何同时支持HTTP和HTTPS协议的实现

    2023-11-19 19:57:05
  • Java实现二分查找的变种

    2023-11-07 11:26:28
  • android实现文本复制到剪切板功能(ClipboardManager)

    2023-11-28 17:40:31
  • springboot常用注释的讲解

    2023-11-03 02:53:15
  • Android打开GPS导航并获取位置信息返回null解决方案

    2021-08-31 09:21:19
  • C#中时间类的使用方法详解

    2023-12-17 13:21:08
  • Java锁之可重入锁介绍

    2021-06-01 03:05:19
  • SparkSQL开窗函数分析使用示例

    2022-04-16 02:26:32
  • Android实现多媒体录音笔

    2022-03-26 17:25:00
  • Java数据类型分类与基本数据类型转换

    2023-08-10 08:33:37
  • C#生成带二维码的专属微信公众号推广海报实例代码

    2023-04-04 23:30:57
  • 使用java基础类实现zip压缩和zip解压工具类分享

    2021-11-23 08:03:41
  • asp之家 软件编程 m.aspxhome.com