Java中自定义注解的使用

2023-10-26

Java中自定义注解的使用

一般来说,市面上有一些的框架,企业都不会直接拿过来就用,通过会做二次开发或封装,为了更加适配自己的开发规范和业务。那么在封装或适配的过程中,自定义注解就起着比较重要的作用。

1 注解定义、原理及作用

1.1 什么是注解

Annotation(注解)是Java5引入的新特性。它提供了一种安全的类似于注解的机制,它可以用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员、变量等)进行关联。为程序的类、方法、成员变量等加上更加直观的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annotation就像一种修饰符一样,应用于包、类型、构造方法、普通方法、成员变量、参数及本地变量的声明语句中。

注解是附加在代码中的一些元信息,用于一些工具在编译、运行时,进行解析和使用,起到说明、配置的功能。
注解不会也不能影响代码的实际逻辑。仅仅起到辅助的作用。包含在java.lang.annotation包中。

1.2 注解的用处

  1. 生成文档。这是最常见的,也是java中提供最早的注释。例如:@param @return等
  2. 跟踪代码依赖性,实现替代配置文件功能。比如@Bean、@Service等,并且可以遇见的是未来的开发,将大量使用注解。
  3. 在编译时进行格式检查。如@Override放在方法上,如果该方法不是覆盖了父类的方法,则编译时就能检查出来。

1.3 注解的原理

注解的本质就是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类,而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

1.4 元注解

java.lang.anntotaion提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要用到元注解):

  • @Documented 注解是否将包含在JavaDoc中
  • @Retention 什么时候使用该注解
  • @Target 注解用于什么地方
  • @Inherited 是否允许子类继承该注解
  1. @Retention - 定义该注解的生命周期
- RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义。因此不会写入
  字节码。@Override,@SuppressWarnings,@Deprecated都属于这类注解。
- RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。`注解默认使用这种方式`
- RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的
  信息。我们`自定义的注解通常使用这种方式`
  1. Target - 表示该注解用于什么地方。默认值为任何元素。
- ElementType.CONSTRUCTOR: 用于描述构造器
- ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
- ElementType.LOCAL_VARIABLE: 用于描述局部变量
- ElementType.METHOD: 用于描述方法
- ElementType.PACKAGE: 用于描述包
- ElementType.PARAMETER: 用于描述参数
- ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明
  1. @Documented - 一个简单的Annotations标记注解,表示是否将注解信息添加到java文档中
  2. @Inherited - 定义该注解和子类的关系
@Inherited元注解是一个标记注解。阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited的注解
被加在了某个类上,那么这个注解将被用于该class的子类。

1.5 Java内置的三大注解(@Override、@Deprecated、@SuppressWarnings)

除上述四种元注解外,JDK预定了另外三种注解:

@Override
@Deprecated
@SuppressWarnings

1.)@Override

java.lang.Override 是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java 编译器将以一个编译错误来警示。

2.)@Deprecated

Deprecated 也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated 修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。

  • 表明已经过时,不推荐使用

3.)@SuppressWarnings

SuppressWarning 不是一个标记类型注解。它有一个类型为String[] 的成员,这个成员的值为被禁止的警告名。对于javac 编译器来讲,被-Xlint 选项有效的警告名也同样对@SuppressWarings 有效,同时编译器忽略掉无法识别的警告名。@SuppressWarnings(“unchecked”)

  • 用于抑制编译器的检查。

2 自定义注解实战

自定义注解类编写的一些规则:

  1. Annotation 型定义为@interface, 所有的Annotation 会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.
  2. 参数成员只能用public 或默认(default) 这两个访问权修饰
  3. 参数成员只能用基本类型byte、short、char、int、long、float、double、boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.
  4. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的方法
  5. 注解也可以没有定义成员,,不过这样注解就没啥用了

自定义注解需要使用到元注解

- 自定义注解会自动继承Annotation接口,无法在继承别的类或接口
- 参数只能用public或默认修饰
- 参数只能用八大基本数据类型+String+Enum等及该类型的数组
- 只能通过反射获取类方法和字段的注解信息
- 注解中可无成员,但那样就没有意义了

①自定义一个水果有关注解

@FruitName:

/**
 * 水果名称注解
 * @author 夏末
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {

    String value() default "";
}

@FruitColor:

/**
 * @author 夏末
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {

    //颜色枚举
    public enum Color{BLUE, RED, GREEN}

    //颜色属性,默认是绿色
    Color fruitColor() default Color.GREEN;
}

@FruitProvider:

/**
 * @author 夏末
 * @description TODO
 * @date 2022/9/29 11:38
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//水果供应商注解
public @interface FruitProvider {

    //水果供应商编号
    public int id() default -1;

    //水果供应商名称
    public String name() default "";

    //供应商地址
    public String address() default "";
}

②定义注解处理器FruitInfoHandler

/**
 * @author 夏末
 * @description 注解处理器
 * @date 2022/9/29 11:40
 */
public class FruitInfoHandler {

    public static void getFruitInfo(Class<?> clazz){
        String strFruitName = " 水果名称: ";
        String strFruitColor = " 水果颜色: ";
        String strFruitProvider = " 供应商信息: ";

        Field[] fields = clazz.getDeclaredFields();

        for(Field field : fields){
            if(field.isAnnotationPresent(FruitName.class)){
                //获取水果名
                FruitName fruitName = (FruitName)field.getAnnotation(FruitName.class);
                strFruitName = strFruitName + fruitName.value();
                System.out.println(strFruitName);
            } else if(field.isAnnotationPresent(FruitColor.class)){
                //获取水果颜色
                FruitColor fruitColor = field.getAnnotation(FruitColor.class);
                strFruitColor = strFruitColor + fruitColor.fruitColor().toString();
                System.out.println(strFruitColor);
            } else if (field.isAnnotationPresent(FruitProvider.class)){
                FruitProvider fruitProvider = field.getAnnotation(FruitProvider.class);
                strFruitProvider = "供应商编号: " + fruitProvider.id() + "供应商名称:" + fruitProvider.name() +
                        "供应商地址: " + fruitProvider.address();
                System.out.println(strFruitProvider);
            }
        }
    }
}

③使用注解(创建某个类并使用注解)

Apple.java:

/**
 * @author 夏末
 * @description 定义一个水果类,并使用注解
 * @date 2022/9/29 11:56
 */
public class Apple {

    @FruitName("Apple")
    private String appleName;

    @FruitColor(fruitColor = FruitColor.Color.RED)
    private String appleColor;

    @FruitProvider(id=1, name = "红富士集团", address = "长虹大道")
    private String appleProvider;

    public String getAppleName() {
        return appleName;
    }

    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }

    public String getAppleColor() {
        return appleColor;
    }

    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }

    public String getAppleProvider() {
        return appleProvider;
    }

    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }
}

④测试结果

public class Test {

    public static void main(String[] args) {
        FruitInfoHandler.getFruitInfo(Apple.class);
        // 水果名称: Apple
        // 水果颜色: RED
        //供应商编号: 1供应商名称:红富士集团供应商地址: 长虹大道
    }
}

参考文章:
https://www.cnblogs.com/UncleWang001/p/11044902.html
https://www.cnblogs.com/zhongqifeng/p/14693074.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java中自定义注解的使用 的相关文章

随机推荐

  • STM32 CAN总线故障检测功能的使用

    STM32 中的CAN总线模块是具有故障监测功能的 就是CANx SCE IRQHandler 这个用的很少 它叫CAN总线状态改变中断 通过打开这个中断 配合代码可以精确的监测CAN总线的故障情况 就是监测对应CAN的ESR寄存器 可以使
  • 常见开源协议介绍

    一 常用开源协议汇总图 首先从一张图开始 介绍几种主流的开源协议 以及决定选用哪种框架的思路 使用哪种开源协议 决定了你发布的开源项目被别人使用了之后 别人的项目是否受到你的项目的开源协议的约束 受到哪种约束 同理 采用别人的开源项目时 也
  • 虚拟机启动报错 :你的设备遇到问题,需要重启。我们只收集某些错误信息,然后为你重新启动......

    解决办法 1 禁用Hyper V 2 禁用Windows虚拟机监控程序平台 3 启用虚拟机平台
  • 利用队列进行数字排序

    OpenJudge利用队列进行数字排序 题目 描述 对于N个数字 有人提出了如下的排序策略 例如 对于数字53 47 85 38 64 23 先建立10个队列 0到9 用于存放数字的大小 将这N个数字依个位存放入各自的队列之中 然后再按队列
  • 免费在线PDF解密

    更好用 传送门
  • LLVM 与 Clang;IR 与AST

    关于LLVM和clang 要说回编译器的组成部分 一 编译器的组成 传统编译器通常由三部分组成 分别是前端 frontEnd 优化器 frontEnd 和 后端 backEnd 在编译过程中 前端主要负责词法 语法分析和语义分析 将源代码转
  • tq210项目启动

    ok210的板子太烂了 居然连jtag口都没有 导致uboot到linux kernel启动调试半天也找不到原因 这次买了这个带jtag的板子 终于可以调试了 有了ok210的经验 这次应该会比较顺利吧 按照原来的打算 先移植uboot d
  • JSONView下载安装

    JSONView下载安装 JSONView概述 JSONView下载 JSONView安装 JSONView测试 JSONView概述 JSONView是一款非常好用的Json格式查看器 在日常开发调试中经常会遇到Json格式的数据需要解析
  • 数据结构之概念,算法,线性表概述

    前言 数据结构在我们编程的过程中是不可避免要遇到的 我们可以去通过学习而选择更高效的数据结构 进而减少我们对内存使用 带来更高的储存效率 基本概念 数据结构为数据 结构 基本操作的结合 数据 数据分为两类 分别为数值型数据和非数值型数据 数
  • 编译过程报错(No rule to make target)

    报错内容 The error make 2 No rule to make target usr lib x86 64 linux gnu libpcl common so needed by range image visualizati
  • C. Recover an RBS

    题目链接 题意 就是给出一个括号序列 其中只包含 这里 可以为 或 问是否该序列是只有一个正确的括号序列 题中保证每个字符串至少有一种正确的括号序列 题解 我们可以分析此题的几个性质 1 题中保证至少有一种正确的括号序列 所以不用去考虑不存
  • 猿创征文

    猿创征文 国产数据库实战之TiDB 数据库快速入门 一 系统检查 1 检查系统版本 2 查看本地IP地址 3 TiDB集群介绍 二 快速部署本地测试集群 1 安装 TiUP工具 2 声明全局环境变量 3 快速部署TiDB 集群 三 连接 T
  • 在ubuntu16.04下安装ElasticSearch-head

    1 安装最新版的nodejs和npm 1 1安装nvm 1 1 1使用git下载对应的包 git clone https github com creationix nvm git nvm cd nvm git checkout git d
  • 关于css 中的visibility属性

    关于css中的visibility属性 就在于是否对用户可见 代码小实例
  • C++ 模板函数特化与重载

    如果程序里有普通模板 模板特化版本 和普通函数 那么程序优先选择普通函数 下面的程序里面打印 normal func include
  • Pycharm2018的激活/破解方法

    https blog csdn net pdcfighting article details 82052055 我用的第二种 激活码激活
  • ADAS&APA场景设计分享

    相信大家都对于ADAS与APA这两个车机功能都不陌生 对其场景设计过程可能并不是很清楚 今天小怿就跟大家分享一下自己的设计心得 首先 我们来看一下ADAS和APA的定义 以便我们更好地了解其功能和应用场景 ADAS定义 ADAS的全称叫Ad
  • html点击显示语音波浪,html5鼠标点击按钮波纹动画特效

    特效描述 html5 鼠标点击 按钮波纹动画 html5按钮波纹动画 代码结构 1 引入CSS 2 引入JS 3 HTML代码 Button A Button B Waves attach flat buttons waves button
  • C++:std::thread:线程用法

    1 std thread的基本用法 最简单的 std thread用法如下 调用 thread将立即同时开始执行这个新建立的线程 新线程的任务执行完毕之后 main 的主线程也会继续执行 include
  • Java中自定义注解的使用

    Java中自定义注解的使用 一般来说 市面上有一些的框架 企业都不会直接拿过来就用 通过会做二次开发或封装 为了更加适配自己的开发规范和业务 那么在封装或适配的过程中 自定义注解就起着比较重要的作用 1 注解定义 原理及作用 1 1 什么是