2025年注解(注解的概念、注解的分类、自定义注解、注解的原理)

注解(注解的概念、注解的分类、自定义注解、注解的原理)一 注解的概念 注释 给人看的 便于阅读代码 对代码的描述 注解 Annotation 对代码的描述 作为代码形式保留下来 Annontation 像一种修饰符一样 应用于包 类型 构造方法 方法 成员变量 参数及本地变量的声明语句中 注释 类似超市商品下面的标签 描述商品 方便给顾客查看的 注解 类似商品的条形码 描述商品

大家好,我是讯享网,很高兴认识大家。

一、注解的概念

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

注解(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 ~ 1999       System.out.println(d.getYear()); //2022 122   } } @SuppressWarnings("all") class Demo2 extends Demo1{   //重写Demo1的   //@Override ​   /     *     * @param a 声明了方法参数     * @return 声明方法返回值     */   @Deprecated   public 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 {   @MyAnnotation1   private int stuno;   private String name; ​   //@MyAnnotation1   public Student( int stuno, String name) {       this.stuno = stuno;       this.name = name;   } ​   public Student() {   } ​   @MyAnnotation1   public 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("....");   }

小讯
上一篇 2025-03-10 22:14
下一篇 2025-03-21 16:12

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/75466.html