java 知识点:注解及使用

注解

  • 大多数时候,我们会使用注解,而不是自定义注解。
  • 注解给谁用?编译器 、给解析程序用
  • 注解不是程序的一部分,可以理解为注解就是一个标签

主要的作用有以下四方面:

  • 生成文档,通过代码里标识的元数据生成 javadoc 文档。

  • 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。

  • 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。

  • 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。

注解的本质

package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 拥有宠物的信息* 宠物的名字* 宠物的年龄*/
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.TYPE)
public @interface Pet {String name();int age();
}

反编译后发现,注解本质上是一个 interface并且继承了 java.lang.annotation.Annotation这个接口.

➜  anno git:(master) ✗ javac Pet.java && javap Pet
警告: 二进制文件Pet包含com.jj.anno.Pet
Compiled from "Pet.java"
public interface com.jj.anno.Pet extends java.lang.annotation.Annotation {public abstract java.lang.String name();public abstract int age();
}

Java 注解(Annotation)是一种元数据形式,提供有关程序代码的额外信息,但这些信息不会影响代码的实际执行。注解可以用于类、方法、变量、参数等程序元素上,以便在编译时、类加载时或运行时进行处理。

元注解

元注解(Meta-Annotations)是用于注解其他注解的注解。元注解提供了对注解进行更精细的控制和定义。

@Retention

@Retention 用于指定注解的保留策略,即注解可以在何时可用。它可以被用于定义其他注解。

public enum RetentionPolicy {/*** Annotations are to be discarded by the compiler.*/SOURCE,/*** Annotations are to be recorded in the class file by the compiler* but need not be retained by the VM at run time.  This is the default* behavior.*/CLASS,/*** Annotations are to be recorded in the class file by the compiler and* retained by the VM at run time, so they may be read reflectively.** @see java.lang.reflect.AnnotatedElement*/RUNTIME
}

@Retention 元注解有一个 value 属性,用于指定保留策略。可选的保留策略包括:

  • RetentionPolicy.SOURCE:注解仅在源代码级别可见,在编译之后不会包含在编译后的字节码中。
  • RetentionPolicy.CLASS:注解在编译时保留,在编译后的字节码中可见,但在运行时不可通过 反射 获取注解信息(默认值)。
  • RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射获取注解信息,并根据注解的定义执行相应的代码,对运行时的代码有影响。

自定义注解的保留策略如果不指定,默认为 RetentionPolicy.CLASS

编译器分别使用了 RuntimeInvisibleAnnotationsRuntimeVisibleAnnotations 属性去记录了 RetentionPolicy.CLASS 注解的方法 和 RetentionPolicy.RUNTIME 方法的注解信息。

@Target

描述注解的作用位置

public enum ElementType {/** Class, interface (including annotation interface), enum, or record* declaration */TYPE,/** Field declaration (includes enum constants) */FIELD,/** Method declaration */METHOD,/** Formal parameter declaration */PARAMETER,/** Constructor declaration */CONSTRUCTOR,/** Local variable declaration */LOCAL_VARIABLE,/** Annotation interface declaration (Formerly known as an annotation type.) */ANNOTATION_TYPE,/** Package declaration */PACKAGE,/*** Type parameter declaration** @since 1.8*/TYPE_PARAMETER,/*** Use of a type** @since 1.8*/TYPE_USE,/*** Module declaration.** @since 9*/MODULE,/*** Record component** @jls 8.10.3 Record Members* @jls 9.7.4 Where Annotations May Appear** @since 16*/RECORD_COMPONENT;
}

@Documented

  • @Documented :用于指定被它注解的注解是否应该包含在自动生成的 API 文档(Javadoc)中。它可以被用于定义其他注解。
  • @Documented :只是一个标记,它本身并不会影响注解的使用和行为。只有在生成 API 文档时才会体现其作用。

通常情况下,如果开发者希望在 API 文档中包含某个注解的信息,就可以为该注解添加 @Documented 元注解。如果不需要在 API 文档中包含注解信息,可以不添加该注解。

@Inherited

@Inherited 用于指定被它注解的 Annotation 是否可以被子类继承。它可以被用于定义其他注解。

自定义注解

@interface 是 Java 中用于创建自定义注解的关键字。使用 @interface 可以定义一个新的注解类型,并在注解中声明自定义的元素。

public @interface 注解名 {// 注解元素声明
}

@interface 定义的花括号中,可以声明注解的元素。

注解元素的定义类似于方法的定义,包括元素的类型、名称和可选的默认值。

注解的属性

属性定义方式与接口中的方法声明方式一样,在注解声明了方法,就同时声明了同名属性变量.

属性的赋值

注解的属性就是接口中定义的方法,定义了属性,就要给属性赋值.

  1. 如果定义属性时,使用 default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值.
  2. 如果注解只声明了一个方法,方法名为 value,则在使用的时候, value 可以省略.
  3. 数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略

属性的返回值

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以上类型的数组

注解解析

在 Java 这个纯面向对象的语言中,一切的行为都是基于的设计来描述,对注解的解析也离不开其所注解的类。

解析注解,主要还是要通过被注解的对象的(class、method、field)来获取。

类上注解解析

在注解的作用对象为@Target(ElementType.TYPE)的基础上

解析步骤为:

  • 获取类字节码信息

  • 获取该class上的注解信息

  • 解析得到注解信息

解析属性上面的字节

在注解的作用对象为@Target(ElementType.FIELD)的基础上。

解析步骤为:

  • 获取类字节码信息

  • 获取字节码中的属性

  • 获取该属性上的注解信息

  • 解析得到注解信息

自定义案例

定义一个枚举

package com.jj.anno;public enum Enumeration {//星期MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}

作用在字段上

package com.jj.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 地址注解*/
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AddressAnnotation {String value() default "";
}

作用在字段上

package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 名字注解*/
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.FIELD)
public @interface NameAnnotation {String name() default "";
}

作用在类型上

package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** 拥有宠物的信息* 宠物的名字* 宠物的年龄*/
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.TYPE)
public @interface Pet {String name();int age();
}

作用在方法上

package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.METHOD)
public @interface MethodAnnotation {String value() default "";
}

作用在类型上

package com.jj.anno;import java.lang.annotation.Retention;
import java.lang.annotation.Target;@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.TYPE)
public @interface Staff {//薪水int value();//岗位名字String title() default "程序员";//工龄int workAge() default 1;Enumeration weekday() default Enumeration.MONDAY;String[] hobbies();AddressAnnotation address();NameAnnotation nickname();Pet pet();
}

使用注解

package com.jj.bean;import com.jj.anno.*;@Pet(name = "jj", age = 18)
@Staff(value = 180000,title = "IT 工程师",workAge = 10,weekday = Enumeration.MONDAY,address = @AddressAnnotation("上海市"),nickname = @NameAnnotation(name = "云溪"),pet = @Pet(name = "jj", age = 18),hobbies = {"打游戏", "看电影"})
public class MyPerson {@NameAnnotation(name = "石昊")private String name;@AddressAnnotation(value = "上海市@宝山区")private String address;public String getName() {return name;}
}

注解解析

package com.jj.bean;import com.jj.anno.*;import java.lang.reflect.Field;public class Main {public static MyPerson initObj() {MyPerson myPerson = new MyPerson();Class<MyPerson> clazz = MyPerson.class;if (clazz.isAnnotationPresent(Pet.class)) {Pet pet = clazz.getAnnotation(Pet.class);System.out.println("宠物的名字:" + pet.name());System.out.println("宠物的年龄:" + pet.age());}if (clazz.isAnnotationPresent(Staff.class)) {Staff staff = clazz.getAnnotation(Staff.class);System.out.println("岗位名字:" + staff.title());System.out.println("工龄:" + staff.workAge());String[] hobbies = staff.hobbies();for (String hobby : hobbies) {System.out.println("兴趣爱好:" + hobby);}Pet pet = staff.pet();System.out.println("宠物的名字:" + pet.name());System.out.println("宠物的年龄:" + pet.age());Enumeration weekday = staff.weekday();System.out.println("工作日:" + weekday);NameAnnotation name = staff.nickname();System.out.println("staff 的 名字:" + name.name());AddressAnnotation address = staff.address();System.out.println("staff 的 地址:" + address.value());}Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true); // 确保可以访问私有字段if (field.isAnnotationPresent(NameAnnotation.class)) {NameAnnotation annotation = field.getAnnotation(NameAnnotation.class);System.out.println("名字: " + annotation.name());try {field.set(myPerson, annotation.name());} catch (IllegalAccessException e) {throw new RuntimeException(e);}}if (field.isAnnotationPresent(AddressAnnotation.class)) {AddressAnnotation annotation = field.getAnnotation(AddressAnnotation.class);System.out.println("地址: " + annotation.value());}}return myPerson;}public static void main(String[] args) {MyPerson myPerson = initObj();System.out.println("通过注解和反射创建的对象:" + myPerson.getName());}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/489487.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图像分割数据集海洋水体船只分割数据集labelme格式6123张3类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;6123 标注数量(json文件个数)&#xff1a;6123 标注类别数&#xff1a;3 标注类别名称:["water","sea_obstacle",&…

Docker Compose--安装本地maven

原文网址&#xff1a;Docker Compose--安装本地maven-CSDN博客 简介 本文介绍如何使用Docker Compose安装maven。 脚本及配置 路径&#xff1a;/work/env/maven ├── app ├── config │ └── settings.xml ├── docker-compose.yml ├── repository └── t…

EDA - Spring Boot构建基于事件驱动的消息系统

文章目录 概述事件驱动架构的基本概念工程结构Code创建事件和事件处理器创建事件总线创建消息通道和发送逻辑创建事件处理器消息持久化创建消息发送事件配置 Spring Boot 启动类测试消息消费运行项目 概述 在微服务架构和大规模分布式系统中&#xff0c;事件驱动架构&#xff…

数据链路层(Java)(MAC与IP的区别)

以太网协议&#xff1a; "以太⽹" 不是⼀种具体的⽹络, ⽽是⼀种技术标准; 既包含了数据链路层的内容, 也包含了⼀些物理 层的内容. 例如: 规定了⽹络拓扑结构, 访问控制⽅式, 传输速率等; 例如以太⽹中的⽹线必须使⽤双绞线; 传输速率有10M, 100M, 1000M等; 以太…

UNIX数据恢复—UNIX系统常见故障问题和数据恢复方案

UNIX系统常见故障表现&#xff1a; 1、存储结构出错&#xff1b; 2、数据删除&#xff1b; 3、文件系统格式化&#xff1b; 4、其他原因数据丢失。 UNIX系统常见故障解决方案&#xff1a; 1、检测UNIX系统故障涉及的设备是否存在硬件故障&#xff0c;如果存在硬件故障&#xf…

黑马程序员Java项目实战《苍穹外卖》Day12

苍穹外卖-day12 课程内容 工作台Apache POI导出运营数据Excel报表 功能实现&#xff1a;工作台、数据导出 工作台效果图&#xff1a; 数据导出效果图&#xff1a; 在数据统计页面点击数据导出&#xff1a;生成Excel报表 1. 工作台 1.1 需求分析和设计 1.1.1 产品原…

【竞技宝】LOL:JDG官宣yagao离队

北京时间2024年12月13日,在英雄联盟S14全球总决赛结束之后,各大赛区都已经进入了休赛期,目前休赛期也快进入尾声,LPL大部分队伍都开始陆续官宣转会期的动向,其中JDG就在近期正式官宣中单选手yagao离队,而后者大概率将直接选择退役。 近日,JDG战队在官方微博上连续发布阵容变动消…

谷歌浏览器的多账户设置与管理

在数字化时代&#xff0c;我们常常需要在不同的网站和服务上使用多个账户。为了方便管理和保护隐私&#xff0c;谷歌浏览器提供了多账户设置功能。本文将详细介绍如何在Chrome中进行多账户设置与管理&#xff0c;并涵盖一些相关的安全配置和问题解决方法。&#xff08;本文由ht…

科研绘图系列:R语言绘制网络图和密度分布图(network density plot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载图1图2图3图4图5图6图7图8系统信息参考介绍 R语言绘制网络图和密度分布图(network & density plot) 加载R包 library(magrittr) library(dplyr) library(…

VRRP的知识点总结及实验

1、VRRP VRRP(Virtual Router Redundancy Protocol&#xff0c;虚拟路由器冗余协议)既能够实现网关的备份&#xff0c;又能解决多个网关之间互相冲突的问题&#xff0c;从而提高网络可靠性。 2、VRRP技术概述&#xff1a; 通过把几台路由设备联合组成一台虚拟的“路由设备”…

数智读书笔记系列002 埃隆·马斯克传

书名&#xff1a;埃隆马斯克传 作者&#xff1a;【美】沃尔特艾萨克森 译者&#xff1a;孙思远&#xff1b;刘家琦 出版社&#xff1a;中信出版集团 出版时间&#xff1a;2023年9月 ISBN&#xff1a;9787521758399 这本书是关于特斯拉CEO埃隆马斯克的传记&#xff0c;作者…

2024年12月13日Github流行趋势

项目名称&#xff1a;nexus-xyz / nexus-zkvm 项目维护者&#xff1a;govereau slumber danielmarinq sjudson yoichi-nexus项目介绍&#xff1a;Nexus zkVM 是一个零知识虚拟机。项目star数&#xff1a;1,948项目fork数&#xff1a;343 项目名称&#xff1a;soxoj / maigret …

016 在路由器上配置 DHCP

配置路由器端口IP地址 将路由器的端口地址配置好&#xff0c; 左边的网络地址是 192.168.1.0 右边的网络地址是 192.168.2.0 配置路由器的DHCP服务 打开命令窗口&#xff0c;进入特权模式 进入全局配置 conf t创建一个DHCP地址池&#xff1b; po1 是地址池的名称&#xf…

使用ElasticSearch实现全文检索

文章目录 全文检索任务描述技术难点任务目标实现过程1. java读取Json文件&#xff0c;并导入MySQL数据库中2. 利用Logstah完成MySQL到ES的数据同步3. 开始编写功能接口3.1 全文检索接口3.2 查询详情 4. 前端调用 全文检索 任务描述 在获取到数据之后如何在ES中进行数据建模&a…

常见软件漏洞修复

1. 3306 MYSQL 升级到最新版&#xff0c;下载地址为 MySQL :: Download MySQL Installer&#xff0c;这里注意&#xff0c;不要跨大版本升级&#xff0c;只升级小版本号&#xff0c;例如mysql5.7.22只需要升级到最新的5.7.44。注意只使用长期维护的稳定版本。设置mysql允许连接…

【C++算法】42.模拟_数青蛙

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a; 题目链接&#xff1a; 1419. 数青蛙 题目描述&#xff1a; 解法 模拟&#xff1a; 利用一个指针&#xff0c;从前往后遍历&#xff0c;遍历到r就看前面有没有c&#xff0c;遍历到o就看前面有没有…

Windows系统VSCode 搭建ESP-IDF环境

VS Code&#xff0c;安装ESP-IDF插件 快捷键CTRLSHIFTP&#xff0c;弹出显示所有命令的窗口&#xff0c;选择ESP-IDF的欢迎 使用第一个选项&#xff0c;要选择一个ESP-IDF版本&#xff0c;选最新的就行 点击Install,等待下载 提示安装成功&#xff0c;如果过程中出现python已存…

Verilog实现图像处理的行缓存Line Buffer

在图像处理中&#xff0c;难免会遇到对图像进行卷积或者模板的局部处理&#xff0c;例如ISP中的一些算法&#xff0c;很大部分都需要一个窗口&#xff0c;在实时视频处理中&#xff0c;可以利用行缓存Line buffer可以暂存几行数据&#xff0c;然后同时输出每行中的对应列的像素…

《庐山派从入门到...》开发板启动

《庐山派从入门到...》开发板启动 什么是固件安装固件 《庐山派从入门到...》开发板启动 什么是固件 **固件可以说是硬件设备的“神经系统”&#xff0c;**它包含了启动序列、设备管理系统和稳定性控制等功能&#xff0c;确保了硬件设备能够安全启动并维持稳定运行。 安装固件…

【PostgreSQL异常解决】PostgreSQL 异常错误: PG::Error 服务意外关闭连接

博主介绍:✌全网粉丝21W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。 感兴趣的可…