一、注解的概念

注释: 给人看的,便于阅读代码, 对代码的描述

注解(Annotation): 对代码的描述, 作为代码形式保留下来,

Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

注释: 类似超市商品下面的标签, 描述商品 方便给顾客查看的

注解: 类似商品的条形码, 描述商品, 方便后期商品结算

注解的本质: 特殊的接口

声明注解: 创建了一个特殊接口

使用注解: @注解名(创建注解的一个对象)

1.注解的作用

1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等 2、跟踪代码依赖性,实现替代配置文件功能。比如Spring的注入,未来java开发,将大量注解配置,具有很大用处; 后期学习框架大量使用, 基于注解的开发 3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出

二、注解的分类:

1.内置注解: jdk定义好这个注解的声明, 开发者直接使用, 语法检查

  • @Override 检测重写

  • @Deprecated 已过时, 只是一个标志, 还是能够使用

  • @SuppressWarnings("all") 抑制编译器生成警告信息

    @SuppressWarnings("all")
    public class Demo1 {@SuppressWarnings("all")public void fun1(){System.out.println("dddd");}
    ​public static void main(String[] args) {Demo2 demo2 = new Demo2();demo2.fun1(10);Date d = new Date();//2022 - 1970 = 52  1900 ~ 1999System.out.println(d.getYear()); //2022  122}
    }
    @SuppressWarnings("all")
    class Demo2 extends Demo1{//重写Demo1的//@Override
    ​/**** @param a  声明了方法参数* @return  声明方法返回值*/@Deprecatedpublic int fun1(int a){return 1;}
    ​
    }

    2.元注解: jdk定义好这个注解的声明, 在注解上使用,

1.@Documented-注解是否将包含在JavaDoc中

一个简单的Annotations标记注解,表示是否将注解信息添加在javadoc文档中

2.@Retention –什么时候使用该注解

Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间

它的取值如下:

  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。

  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

    自定义注解: 保留期一定设置为runtime

    3.@Target–注解用于什么地方

默认值为任何元素,表示该注解用于什么地方。可用的ElementType参数包括 ● ElementType.CONSTRUCTOR:用于描述构造器 ● ElementType.FIELD:成员变量、对象、属性(包括enum实例) ● ElementType.LOCAL_VARIABLE:用于描述局部变量 ● ElementType.METHOD:用于描述方法 ● ElementType.PACKAGE:用于描述包 ● ElementType.PARAMETER:用于描述参数 ● ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明

4.@Inherited – 定义该注释和子类的关系

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解

/*** 定义一个注解接口*  使用元注解对自定义的注解进行一些声明,说明*/
@Documented  //表示该MyAnnotation1注解将会在生成doc文档上出现
//跟注解的参数赋值: 如果数组类型
@Target(value={ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})    //目标: 表示这个MyAnnotation1注解在那些地方使用// 如果没有写, 表示这个注解在任意的地方使用
@Retention(value= RetentionPolicy.RUNTIME) //自定义注解,保留期一定是Runtime
@Inherited // 表示这个MyAnnotation1这个注解标记的类, 这个类的子类是否继承父类该注解
public @interface MyAnnotation1 {
​
}
@MyAnnotation1  //创建了MyAnnotation1的一个对象
​
public class Student {@MyAnnotation1private int stuno;private String name;
​//@MyAnnotation1public Student( int stuno, String name) {this.stuno = stuno;this.name = name;}
​public Student() {}
​@MyAnnotation1public int getStuno() {return stuno;}
​public void setStuno(int stuno) {this.stuno = stuno;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​
}
​
class  SubStudent extends  Student{
​
}

三、自定义注解

  1. 自定义注解: 关键字@interface , 默认继承Annotation接口, 本质就是一个接口

  2. 参数成员访问修饰符: public 或者是缺省的(还是public), 参数名后面必须是()

参数本质就是一个抽象方法

但是我们可以使用注解的时候,给参数赋值, 在声明的时候, 设置默认值

参数名() default 值;

如果一个参数没有设置default默认值, 使用这个注解的时候, 一定要给参数赋值,

如果使用default, 使用注解的时候, 可以给参数赋值,也可以不赋值(使用默认值)

  1. 参数的数据类型: 八大基本数据类型,String, 枚举,Class,注解类型,或者12种的数组类型

  2. 自定义的注解,可以有参数,也可以没有参数, 如果没有参数,这个注解没有意义

  3. 自定义注解,它的功能, 必须写代码解析注解,并给它赋予功能,自定义注解保留期: 一定为RUNTIME, 获取该注解的对象, 只能使用反射来获取

  • 自定义注解:

    声明注解的语法: @interface

    public @interface 注解名{
    //成员
    }

    使用注解:

    在方法,类型,包,构造方法,属性,参数... 使用注解

    @注解名

使用注解注意事项:

  1. 如果注解定义的参数是数组类型, 给数组类型赋值

a. 赋一个值: 参数名=值 或者: 参数名={值}

b. 赋多个值: 参数名={值1,值2,值3....}

/*** 自定义注解
*/
@Documented
@Target(value={ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Annotation1 {//成员参数// value参数有一个默认值, 这个方法默认返回值//给这个参数赋值, 就是设置这个方法的返回值String value();SexEnum sex() default SexEnum.MAN;
}
​
​
public enum SexEnum {MAN,WOMAN
}
@Annotation1(value="lisi",sex=SexEnum.WOMAN)
public class Demo3 {
}

商品类: 上架方法, 下架方法, 购买方法, 浏览方法,

/*** 商品类*/
public class Product {
​@Role("管理员")public void shangJia(){System.out.println("商品正在上架...");}
​@Role("管理员")public void xiaJia(){System.out.println("商品正在下架...");}
​@Role("顾客")public void buy(){System.out.println("您正在购买商品...");}
​public void look(){System.out.println("您正在查看商品...");}
}
/*** 角色的注解*/
//如果这个参数名为value, 单独给这个value参数赋值, 省略 value=// 如果给多个参数赋值, value= 一定不能省略
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Role {String value();
}

要求: 上架方法, 下架方法,必须要求用户的角色是"管理员"

购买方法: 必须要求用户的角色是"顾客"

浏览方法: 不需要角色

        
Scanner input = new Scanner(System.in);System.out.println("请输入您的角色:");String role = input.next();System.out.println("请输入您的调用的方法:");String methodName = input.next();
​//调用Product的方法Product product = new Product();//调用方法之前,判断你的角色与方法上定义的角色是否匹配//如果不匹配, 禁止访问, 如果匹配,允许访问//通过反射//1.获取Product类的Class对象Class<Product> clazz = Product.class;//2.获取指定方法名的Method对象Method method = clazz.getDeclaredMethod(methodName);//判断您的角色是否满足//3.获取这个方法上的需要角色: 使用注解//判断是否有@Role注解  isAnnotationPresent(注解的Class类型) true表示有, false:没有if(method.isAnnotationPresent(Role.class)){ //true//判断角色是否匹配//获取这个方法上@Role的value参数//获取方法上的注解对象  getAnnotation(类<A> annotationClass) 获取指定类型的注解对象//Annotation[] getAnnotations() 获取所有的注解对象Role obj = method.getAnnotation(Role.class);//获取它的参数值String value = obj.value();if(role.equals(value)){ //角色是否匹配System.out.println("您有权限访问...");method.invoke(product);}else{System.out.println("您没有权限访问...");}
​}else{//没有,直接执行method.invoke(product);}//3.调用方法//method.invoke(product);

四、注解的原理:

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

 这个运行时生成的动态代理对象是可以导出到文件的,方法有两种

  • 在代码中加入System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

  • 在运行时加入jvm 参数 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

 public static void main(String[] args) throws NoSuchMethodException {System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");Class<Test> clazz = Test.class;Method method = clazz.getMethod("fun");Role annotation = method.getAnnotation(Role.class);System.out.println(annotation);}
​@Role(value="xxx")public static void fun(){System.out.println("....");}

注解(注解的概念、注解的分类、自定义注解、注解的原理)相关推荐

  1. 自定义依赖注解无效_关于Apt注解实践与总结【包含20篇博客】

    超详细!安卓巴士开发者大会嘉宾及主题介绍 目录介绍 00.注解系列博客汇总 01.什么是apt 02.annotationProcessor和apt区别 03.项目目录结构 04.该案例作用 05.使 ...

  2. 自定义Java注解(一)

    概念 注解是Java语言5.0版本开始支持加入源代码的特殊语法元数据(描述数据的数据)有点像Class(描述类的类) 要自定义注解,必须先了解Java提供的几个基本的元注解及其相关的语法 Java的几 ...

  3. Java注解的基本概念和原理及其简单实用

      一.注解的基本概念和原理及其简单实用 注解(Annotation)提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化得方法,使我们可以在稍后某个时刻方便的使用这些数据(通过解析 ...

  4. 自定义依赖注解无效_SpringValidation用注解代替代码参数校验解析

    Spring Validation 概念 在原先的编码中,我们如果要验证前端传递的参数,一般是在接受到传递过来的参数后,手动在代码中做 if-else 判断,这种编码方式会带来大量冗余代码,十分的不优 ...

  5. java 自定义注解 生成json_Java中如何创建自定义的注解

    前言 关于Java的注解,我一直在用,没有太搞明白它的原理,至于如何自定义一个注解,就更不明白了.其实参考的这篇文章,之前看过一遍,当时以为看懂了,但是最近在工作中去印证的时候,发现对注解还是不理解, ...

  6. Java中如何创建自定义的注解学习笔记(MD版)

    概要 Java中如何创建自定义的注解学习笔记(MD版). 博客 博客地址:IT老兵驿站. 前言 记得这篇笔记还是在泉州的龙玲酒店记录的,是一个周六的晚上,坐飞机从上海到泉州,从笔记中能勾起一些旅游的回 ...

  7. Spring MVC代码实例系列-06:Spring MVC配置Hibernate-Validator以及自定义校验注解

    超级通道 :Spring MVC代码实例系列-绪论 本章主要记录,如何在Spring MVC中添加Hibernate-Validator以及自定义校验注解.本章主要涉及的技术点有: javax.val ...

  8. Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件

    本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...

  9. SpringBoot conditional注解和自定义conditional注解使用

    conditional注解是Springboot starter的基石,自动装配的时候会根据条件确定是否需要注入这个类. 含义:基于条件的注解. 作用:根据是否满足某个特定条件来决定是否创建某个特定的 ...

  10. 自定义Android注解Part3:绑定

    上一节我们已经将自动生成注解代码部分介绍完毕,今天这篇文章是自定义Android注解系列的最后一篇文章.希望大家这一路走来有所收获. 经过前面的了解,我们三大部分:butterknife-annota ...

最新文章

  1. docker mysql详解_Docker轻松入门(详解)
  2. 六大“未来式”存储器,谁将脱颖而出?
  3. 主成分分析(PCA)——以2维图像为例
  4. 字典树(Trie tree)
  5. 【WinForm-无边框窗体】实现Panel移动窗体,没有边框的窗体
  6. python selenium环境配置Firefox和Chrome
  7. Pytorch-张量的创建与使用方法
  8. linux vi只写入1个字节,关于linux命令的说明(这是一个命令集)
  9. 计算机教室电脑无法启动,电子教室教师端不能启动没开机的学生机的解决办法...
  10. 模拟轮盘抽奖游戏:一等奖、二等奖、三等奖
  11. 自费访学|计算机专业老师赴加拿大卡尔加里大学
  12. android手机电池寿命,手机用多久换电池比较合适?
  13. 年薪百万阿里前端工程师分享——Web应用实例:音频可视化
  14. 遇见未来 | 对话朱贤文: PostgreSQL是一匹即将发力的黑马
  15. WIN10解包分区和磁盘分区教程
  16. quot;title_activity_distquot; is not translated in quot;zh-rCNquot; (Chinese: China)
  17. Android 源码编译技巧--模块清理
  18. 2W字!详解20道Redis经典面试题!(珍藏版)
  19. python打印hello word_在屏幕上打印输出Hello World,使用的Python语句是( )_学小易找答案...
  20. ai电销机器人系统搭建源码-CRM模块

热门文章

  1. 用Paddlepaddle实现车辆逆行违章检测
  2. mysql 存储文本数据类型_MYSQL中的五种数据类型
  3. 【patsubst函数】
  4. 基于扭曲的后门攻击——WANET – IMPERCEPTIBLE WARPING-BASED BACKDOOR ATTACK
  5. 用AI保护货车司机安全,总共分几步?
  6. 未来鸿蒙能搭载oppo手机吗,【喂你播】华为下周发布鸿蒙手机系统;OPPO联合蔚来完成CCC2.0标准数字车钥匙开发...
  7. patch-wise分类
  8. 侧边导航栏(抽屉式设计)界面 (html + css)
  9. C++作业: 五人合伙夜间捕鱼,天亮前因劳累在河边相继分别找地方睡去
  10. 练习:编写10个线程,第一个线程从1加到10,第二个线程从11加到20...第十个线程从91加到100,最后再把十个线程结果相加