Java基础-注解

注解

    • 注解是用来干什么的
    • 它有什么作用
    • 注解的常见分类
    • 内置注解
      • @Override
        • 注解定义
      • @Deprecated
        • 注解定义
      • @SuppressWarnings
        • 注解定义
    • 元注解
      • @Target
        • 注解定义
        • ElementType
      • @Retention&&@RetentionTarget
        • 注解定义
        • RetentionPolicy
      • @Documented
        • 注解定义
      • @Inherited
        • 注解定义
        • 用法
      • Repeatable(重复注解)
        • 注解定义
        • JDK8之前
        • JDK8之后
      • Native
    • 注解与反射接口
        • 相关接口
    • 自定义注解
    • 注解的本质(未完结)

注解是用来干什么的

注解的汉语意思: 用浅近的文字解释艰深的词句

注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包,类,接口,字段,方法参数,局部变量进行注解.

它有什么作用

主要作用是下面四个方面

  • 生成文档
    通过代码里标识的元数据生成javaDoc文档
  • 编译检查
    通过代码里标识的元数据让编译器在编译期间进行检查验证
  • 编译时动态处理
    编译时通过代码里标识的元数据动态处理,例如动态生成代码
  • 运行时动态处理
    运行时通过底阿妈里标识的元数据动态处理,例如使用反射注入实例

注解的常见分类

  • Java自带的标准注解
    用于标明重写某个方法,某个类或方法过时,表明要忽略的警告,用这些注解表明后编译器就会 进行检查
  • 元注解
    用于定义注解的注解
  • 自定义注解
    根据自己的需求定义注解,并可用元注解对自定义注解进行注解

内置注解

@Override

表示当前的方法定义将覆盖父类中的方法

注解定义
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

这个注解可以用来修饰方法,并只在编译期有效,编译期后class文件就不存在了

@Deprecated

表示代码被弃用,如果使用了被@Deprecated注解的代码编译器会发出警告

注解定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
  1. 它会被文档化
  2. 可以保留到运行时
  3. 可以修饰构造方法,属性,局部变量,方法,包,参数,类型

@SuppressWarnings

关闭编译器警告信息

注解定义
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {String[] value();
}
  1. 可以修饰类型,属性,方法,参数,构造器,局部变量
  2. 只能存活在源码
  3. 取值为String[]
    它可以取的值如下所示:
参数作用
all抑制所有警告
deprecation抑制启用注释的警告
finally抑制finally模块没有返回的警告
null忽略对null的操作
unused抑制没被使用过的代码的警告
等等

元注解

@Target

描述注解的使用范围(即被修饰的注解可以在什么地方使用)

注解定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {/*** Returns an array of the kinds of elements an annotation interface* can be applied to.* @return an array of the kinds of elements an annotation interface* can be applied to*/ElementType[] value();
}
  1. 可被文档化
  2. 可以保留到运行时
  3. 只能在注解类上使用
  4. value值在ElementType中
ElementType
public enum ElementType {TYPE, // 类、接口、枚举类FIELD, // 成员变量(包括:枚举常量)METHOD, // 成员方法PARAMETER, // 方法参数CONSTRUCTOR, // 构造方法LOCAL_VARIABLE, // 局部变量ANNOTATION_TYPE, // 注解类PACKAGE, // 可用于修饰:包TYPE_PARAMETER, // 类型参数,JDK 1.8 新增TYPE_USE // 使用类型的任何地方,JDK 1.8 新增}

@Retention&&@RetentionTarget

描述注解保留的时间范围(即被描述的注解在它所修饰的类中可以被保留到何时)

注解定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {RetentionPolicy value();
}
  1. 可被文档化
  2. 可以保留到运行时
  3. 只能在注解类上使用
  4. value值在RetentionPolicy 中
RetentionPolicy
public enum RetentionPolicy {SOURCE,    // 源文件保留CLASS,       // 编译期保留,默认值RUNTIME   // 运行期保留,可通过反射去获取注解信息
}

我们可以通过执行javap -verbose RetentionTest获取到RetentionTest的class字节码内容如下.

{public retention.RetentionTest();flags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 3: 0public void sourcePolicy();flags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnLineNumberTable:line 7: 0public void classPolicy();flags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnLineNumberTable:line 11: 0RuntimeInvisibleAnnotations:0: #11()public void runtimePolicy();flags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnLineNumberTable:line 15: 0RuntimeVisibleAnnotations:0: #14()
}

我们可以得到下面的两个结论:

  1. 编译期没有记录下sourcePolicy()方法的注解信息
  2. 编译期分别使用了RuntimeInvisibleAnnotations, RuntimeVisibleAnnotations 属性去记录了classPolicy()方法和runtimePolicy()方法的注解信息

@Documented

描述使用javaDoc工具为类生成帮助文档时是否要保留其注解信息

注解定义
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface TestDocAnnotation {public String value() default "default";
}
  1. 可被生成文档
  2. 使用范围是类,接口,枚举类,成员方法

@Inherited

被他修饰的注解具有继承性.
如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注释

注解定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
  1. 可被生成文档
  2. 可被保留到运行时
  3. 只能用于注解类
用法

定义@Inherited注解

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface TestInheritedAnnotation {String [] values();int number();
}

使用这个注解

@TestInheritedAnnotation(values = {"value"}, number = 10)
public class Person {
}class Student extends Person{@Testpublic void test(){Class clazz = Student.class;Annotation[] annotations = clazz.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation.toString());}}
}

输出内容

xxxxxxx.TestInheritedAnnotation(values=[value], number=10)

即使Student类没有显示地被注解@TestInheritedAnnotation,但是它的父类Person被注解,而且@TestInheritedAnnotation@Inherited注解,因此Student类自动有了该注解.

Repeatable(重复注解)

允许在同一申明类型(类,属性,方法)多次使用同一注解

注解定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {Class<? extends Annotation> value();
}
  1. 可被生成文档
  2. 可以保留至运行时
  3. 只能作用域注解类
JDK8之前

JDK8之前有重复使用注解的解决方案,但是可读性不好
方案: 由另一个注解来存储重复注解,在使用的时候,用存储注解Authorities来扩展重复注解

public @interface Authority {String role();
}public @interface Authorities {Authority[] value();
}public class RepeatAnnotationUseOldVersion {@Authorities({@Authority(role="Admin"),@Authority(role="Manager")})public void doSomeThing(){}
}
JDK8之后

方案: 创建重复注解时,加上@Repeatable,指向存储注解Authorities,在使用的时候,可以直接重复使用Authority注解.

@Repeatable(Authorities.class)
public @interface Authority {String role();
}public @interface Authorities {Authority[] value();
}public class RepeatAnnotationUseNewVersion {@Authority(role="Admin")@Authority(role="Manager")public void doSomeThing(){ }
}

Native

使用@Native注解修饰成员变量,表示这个变量可以被本地代码引用,常常被代码生成工具使用,了解即可.

注解与反射接口

我们如果想自定义注解,那么就必须先了解注解与反射接口的这部分内容.
反射包java.lang.reflect下的AnnotatedElement接口提供这些方法.
注意:只有注解被定义为RUNTIME后,该注解才能是运行时可见,当class文件被装载时,被保存在class文件中的Annotation才会被虚拟机读取.

AnnotatedElement接口是所有程序元素(Class,Method,Constructor)的父接口.

Classpublic final class Class<T> implements Serializable, GenericDeclaration, Type, AnnotatedElement, TypeDescriptor.OfField<Class<?>>, Constable {
xxxx
}
Methodpublic final class Method extends Executable {
xxx
}
public abstract sealed class Executable extends AccessibleObject{
xxx
}
public class AccessibleObject implements AnnotatedElement {
xxx
}Constructorpublic final class Constructor<T> extends Executable {
xxx
}
和上面Method的继承路径是是一样的,不赘述了.
相关接口
  • boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)
    判断该元素上是否包含指定类型的注解,存在则返回true,否则返回false.
    (此方法会忽略注解对应的注解容器)
  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)
    返回该程序元素上存在的,制定类型的注解,如果该类型的注解不存在,则返回null
  • <Annotation[] getAnnotations()
    返回该程序元素上存在的所有注解,若没有注解,返回长度为0的数组
  • <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
    返回该程序元素上存在的,指定类型的注解数据.若没有,返回长度为0的数组
    该方法调用者可以随意修改返回数据,不会对其他调用者返回数组产生影响.
    (会检测注解对应的重复注解容器)
  • <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass
    返回直接存在此元素上的所有注解.
    该方法忽略继承的注解,如果没有注解直接存在此元素上,返回null.
  • <T extends Annotation> T[] getDeclaredAnotationsByType(Class<T> annotationClass)
    返回直接存在此元素上所有指定类型注解,
    该方法忽略继承的注解
  • Annotion[] getDeclaredAnnotations()
    返回直接存在于此元素上的所有注解机器注解对应的重复注解容器.
    该方法忽略继承注解,如果没有注释直接存在于此元素上,则返回长度为零的一个数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。

自定义注解

理解注解与反射接口后,我们通过自定义注解来把知识点融合应用一下

  • 定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethodAnnotation {public String title() default "";public String description() default "";}
  • 使用注解
public class TestMethodAnnotation {@Override@MyMethodAnnotation(title = "toStringMethod", description = "override toString method")public String toString() {return "Override toString method";}@Deprecated@MyMethodAnnotation(title = "old static method", description = "deprecated old static method")public static void oldMethod() {System.out.println("old method, don't use it.");}@SuppressWarnings({"unchecked", "deprecation"})@MyMethodAnnotation(title = "test method", description = "suppress warning static method")public static void genericsTest() throws FileNotFoundException {List l = new ArrayList();l.add("abc");oldMethod();}
}
  • 用反射接口获取注解信息
public static void main(String[] args) {try {// 获取所有methodsMethod[] methods = TestMethodAnnotation.class.getClassLoader().loadClass(("com.pdai.java.annotation.TestMethodAnnotation")).getMethods();// 遍历for (Method method : methods) {// 方法上是否有MyMethodAnnotation注解if (method.isAnnotationPresent(MyMethodAnnotation.class)) {try {// 获取并遍历方法上的所有注解for (Annotation anno : method.getDeclaredAnnotations()) {System.out.println("Annotation in Method '"+ method + "' : " + anno);}// 获取MyMethodAnnotation对象信息MyMethodAnnotation methodAnno = method.getAnnotation(MyMethodAnnotation.class);System.out.println(methodAnno.title());} catch (Throwable ex) {ex.printStackTrace();}}}} catch (SecurityException | ClassNotFoundException e) {e.printStackTrace();}
}
  • 测试的输出
Annotation in Method 'public static void com.pdai.java.annotation.TestMethodAnnotation.oldMethod()' : @java.lang.Deprecated()
Annotation in Method 'public static void com.pdai.java.annotation.TestMethodAnnotation.oldMethod()' : @com.pdai.java.annotation.MyMethodAnnotation(title=old static method, description=deprecated old static method)
old static method
Annotation in Method 'public static void com.pdai.java.annotation.TestMethodAnnotation.genericsTest() throws java.io.FileNotFoundException' : @com.pdai.java.annotation.MyMethodAnnotation(title=test method, description=suppress warning static method)
test method
Annotation in Method 'public java.lang.String com.pdai.java.annotation.TestMethodAnnotation.toString()' : @com.pdai.java.annotation.MyMethodAnnotation(title=toStringMethod, description=override toString method)
toStringMethod

注解的本质(未完结)

这部分要扯到动态代理和注解的处理器,emmm比较麻烦.
后面发完动态处理后返回来填坑

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

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

相关文章

低代码开发:推动互联网企业数字化转型的关键因素

联网行业作为我国数字经济发展的核心驱动力&#xff0c;在推动国家数字化转型中扮演着至关重要的角色。与其他传统行业相比&#xff0c;互联网企业面临更加紧迫的数字化转型需求&#xff0c;因为它们需要不断适应快速变化的市场环境和技术趋势。 然而&#xff0c;由于互联网企业…

深入理解APDU协议与Java开发

1. 什么是APDU&#xff1f; APDU&#xff0c;即应用协议数据单元&#xff08;Application Protocol Data Unit&#xff09;&#xff0c;是一种在智能卡与卡片读卡器之间进行通信的协议。APDU定义了在交互中传输的数据格式和规则&#xff0c;允许读卡器发送指令并接收响应。 2…

MFC 皮肤库配置

1.创建MFC 对话框 2.添加皮肤资源 添加资源 添加头文件 关闭SDL检测 添加静态库文件 修改字符集 添加头文件 将皮肤中的ssk文件加载到初始化实例中 > 运行即可

springboot 的 websocket 里面使用 @Autowired 注入 service 或 bean 时,报空指针异常

直接上解决方案&#xff1a; 在你的WebSocketServer服务器中 public static MessageService messageService; //要注入的类// 注入的时候&#xff0c;给类的 service 注入Autowiredpublic void setChatService(MessageService messageService) {WebSocketServer.messageSer…

【寸铁的刷题笔记】树、dfs、bfs、回溯、递归(一)

【寸铁的刷题笔记】树、dfs、bfs、回溯、递归(一) 大家好 我是寸铁&#x1f44a; 总结了一篇刷题关于树、dfs、bfs、回溯、递归的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 105. 从前序与中序遍历序列构造二叉树 模拟分析图 代码实现 /*** Definition for a binary tre…

HarmonyOS—添加/删除Module

Module是应用/服务的基本功能单元&#xff0c;包含了源代码、资源文件、第三方库及应用/服务配置文件&#xff0c;每一个Module都可以独立进行编译和运行。一个HarmonyOS应用/服务通常会包含一个或多个Module&#xff0c;因此&#xff0c;可以在工程中创建多个Module&#xff0…

如何利用内网穿透工具在企业微信开发者中心实现本地接口服务回调

文章目录 1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 企业微信开发者在应用的开发测试阶段&#xff0c;应用服务通常是部署在开发环境&#xff0c;在有数据回调的开发场…

SQL查询每个类别价格前3的数据

SELECTproduct_id,category,price FROM (SELECTproduct_id,category,price,ROW_NUMBER() OVER (PARTITION BY category ORDER BY price) AS rankFROMyour_products_table ) AS ranked_products WHERErank < 3;DENSE_RANK() 和 ROW_NUMBER() 是窗口函数&#xff08;Window Fu…

前端知识复习

1.symbol类型 Symbol 是 ECMAScript 6 中引入的一种新的基本数据类型&#xff0c;它表示独一无二的值。Symbol 值是通过 Symbol() 函数创建的。 Symbol 值具有以下特点&#xff1a; 独一无二性&#xff08;唯一性&#xff09;&#xff1a;每个通过 Symbol() 函数创建的 Symb…

十三:集合

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 01、Java 集合框架概述1.1、集合框架与数组的对比及概述1.2、集合框架涉及到的API 02、Collection接口方法2.1、Collection接口中的常用方法12.2、Collection接口中…

在idea中配置Tomcat

1.在idea中点击右上角 2.点击Edit Configurations,点击加号 3.向下拉找到Tomcat Server下的Local,点一下 点击Configure 找到tomcat文件路径,选择apache-tomcat-8.5.63(8.5.63是我的版本号) 选择好路径后点ok就配置好了 总步骤:

Vue 图片轮播第三方库 Vue-awesome-swiper介绍及简单例子

vue-awesome-swiper 是一个基于 Swiper 的 Vue 轮播图组件&#xff0c;Swiper 是一个流行的移动端触摸滑动插件。它为 Vue.js 应用提供了一套丰富的轮播组件&#xff0c;支持多种布局和功能&#xff0c;如自动播放、无限循环、触摸滑动等。 安装 首先&#xff…

代码随想录算法训练营第一天

● 今日学习的文章链接和视频链接 ● 自己看到题目的第一想法 1. 704二分法&#xff1a; 方法一&#xff1a; 整个数组是 左闭右闭区间 [ ] left指针指向数组开始下标&#xff0c; right 指针指向数组最后下表nums.size()-1, mid为 (leftright) /2循环条件 left<rightnu…

打开stable diffusion webui时,提示缺少clip或clip安装不上的解决方案(windows下的操作)

1.问题描述 打开stable diffusion webui时&#xff0c;提示缺少clip或clip安装不上 2.解决方案 原因&#xff1a;stable diffusion webui环境中的clip其实是open_clip&#xff0c;不能用pip install clip安装解决方法是直接到github下载 open_clip 代码到本地&#xff0c;并…

linux环境ssh-rsa进行签名\权限\登录\原理(免密登录)

linux环境ssh-rsa进行签名权限登录(免密登录) SSH原理与运用什么是SSH?SSH的使用场景ssh-rsa获取xshell环境登录获取ssh-rsa使用ssh-rsa登录SHA系列SHA-1、SHA-256和RSA的区别RSA原理数论基础RSA机制RSA数学密钥生成公式RSA数学加密理论RSA数学签名公式

小折叠也能成为主力机,全新小折叠旗舰华为Pocket 2正式发布

2024年2月22日&#xff0c;华为在三亚举办华为Pocket 2时尚盛典&#xff0c;正式发布其全新小折叠旗舰华为Pocket 2。一直以来&#xff0c;华为致力于萃取各界艺术灵感&#xff0c;不断探寻科技美学的可能性&#xff0c;华为Pocket系列更是秉承将奢雅美学与尖端科技融为一体的理…

探索Redis是否为单线程的奥秘(文末送书)

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. Redis中的多线程二. I/O多线程三. Redis中的多进程四. 结论五. 书籍推荐5.1 书…

高效时间管理法则

你是否天天在忙&#xff0c;是否忙的不得要领&#xff0c;认真领会时间管理的四象限工作法&#xff0c;它会让你的工作变得高效。 目录 一、时间管理的误区 二、时间是如何被浪费的&#xff1f; 内部因素 外部因素 三、时间管理的5个阶段 1.公鸡型时间管理&#xff1a; …

第一个Qt程序中的秘密

创建第一个程序 首先我们打开Qt Creator 打开文件->New Projects... 菜单&#xff0c;创建我们的第一个Qt项目 选择 Qt Widgets Application&#xff0c;点击选择...按钮 之后&#xff0c;输入项目名称QtLearning&#xff0c;并选择创建路径&#xff0c; 在build system中选…

ConnectWise ScreenConnect 身份验证绕过漏洞复现可RCE(CVE-2024-1709)

0x01 产品简介 ConnectWise ScreenConnect ,是一款自托管的远程桌面软件应用,该款软件允许用户自行托管,可以在自己的服务器、个人电脑、虚拟机或虚拟专用服务器上运行。 0x02 漏洞概述 ConnectWise ScreenConnect低于23.9.8 版本的产品中,SetupWizard.aspx接口处存在身…