0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

JAVA中注解是怎么做到的(下)

jf_78858299 来源:JAVA旭阳 作者:JAVA旭阳 2023-05-11 10:57 次阅读

使用反射操作注解

大部分情况下,我们的项目或者开源框架中都定义了大量的注解,而且都是@Retention(RetentionPolicy.RUNTIME)运行时阶段,我们可以通过反射获取注解中的信息,所以整体遵循下面的一个范式。

  1. 自定义注解
  2. 扫描注解
  3. 通过反射获取注解的信息,执行相应的逻辑。

下面我们重点使用下如何用反射来获取注解的信息。

  1. 定义target是注解的注解
@Inherited
@Retention( value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.ANNOTATION_TYPE})
public @interface AnnoTest {

    String value() default "anno";

}
  1. 定义一个几乎全量信息的注解
@AnnoTest("alvinAnno")
@Inherited
@Retention( value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE_USE,ElementType.PACKAGE,ElementType.FIELD,
        ElementType.TYPE_PARAMETER,ElementType.CONSTRUCTOR,ElementType.LOCAL_VARIABLE})
@Documented
public @interface FullAnnoTest {

    String value() default  "FullAnnoTest";

}
  1. 定义测试类和反射代码
@FullAnnoTest("package")
package com.alvin.java.core.anno;

public class ParentObj {
}



@FullAnnoTest("testAnnoReflect")
public class TestAnnoReflect<@FullAnnoTest("parameter") T > extends @FullAnnoTest("parent")ParentObj {

    @FullAnnoTest("constructor")
    TestAnnoReflect() {
    }

    //注解字段域
    private @FullAnnoTest("name") String name;
    //注解泛型字段域
    private @FullAnnoTest("value") T value;
    //注解通配符
    private @FullAnnoTest("list") List<@FullAnnoTest("generic") ?> list;
    //注解方法
    @FullAnnoTest("method")                       //注解方法参数
    public String hello(@FullAnnoTest("methodParameter") String name)
            throws @FullAnnoTest("Exception") Exception { // 注解抛出异常
        //注解局部变量,现在运行时暂时无法获取(忽略)
        @FullAnnoTest("result") String result;
        result = "siting";
        System.out.println(name);
        return  result;
    }

    public static void main(String[] args) throws Exception {

        TestAnnoReflect
  1. 查看对应的执行结果
修饰TestAnnoReflect.class注解value: testAnnoReflect
修饰构造器的注解value: constructor
修饰继承父类的注解value: parent
修饰注解的注解AnnoTest-value: alvinAnno
修饰泛型参数T注解value: parameter
修饰普通字段域name注解value: name
修饰泛型字段T注解value: value
修饰泛型注解value: list
修饰通配符注解value: generic
修饰方法的注解value: method
修饰方法抛出错误的注解value: Exception
修饰方法参数注解value: methodParameter
修饰package注解value: package
hello

注解的本质和底层实现

大家有没有想过注解的本质是什么?

我们先通过反编译查看注解生成的字节码,可以通过javap -v FullAnnoTest.class查看如下:

图片

可以看到,我们的注解是继承自Annotation接口

public interface Annotation {
    boolean equals(Object obj);

    int hashCode();

    String toString();

    /**
     * Returns the annotation type of this annotation.
     * @return the annotation type of this annotation
     */
    Class? extends Annotation annotationType();
}

所以注解相当于一个语法糖一样,可以方便我们使用,本质上它是继承自Annotation的一个接口。

那大家有没有想过它的实现类在哪里?比如下面的代码,获取到注解,按照上面的解释,它是一个接口,那调用value()方法时,它具体调用的哪个实现类呢?我们并没有写实现类啊.....

答案当然就是动态代理生成的实现类。

AnnoTest annoTest = testTmp.annotationType().getAnnotation(AnnoTest.class);
System.out.println("修饰注解的注解AnnoTest-value: "+annoTest.value());

我们可以在启动参数添加如下命令可以查看生成的代理类:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

图片

执行后,生成代理类如下,

图片

代理大致的代码如下:

public final class $Proxy2 extends Proxy implements FullAnnoTest {
    private static Method m1;
    private static Method m2;
    private static Method m4;
    private static Method m0;
    private static Method m3;

    public $Proxy2(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

  

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String value() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.alvin.java.core.anno.FullAnnoTest").getMethod("annotationType");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("com.alvin.java.core.anno.FullAnnoTest").getMethod("value");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

我们看value()方法,这里调用了super.h对象,也就是InvocationHandler对象,而我们注解用的是AnnotationInvocationHandler这个子类,我们在invoke方法中打个断点,就明白了~~

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102994
  • JDK
    JDK
    +关注

    关注

    0

    文章

    77

    浏览量

    16489
  • spring框架
    +关注

    关注

    0

    文章

    7

    浏览量

    2023
收藏 人收藏

    评论

    相关推荐

    Java中注解的作用

    Annotation 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量
    的头像 发表于 09-30 10:12 319次阅读
    <b class='flag-5'>Java</b><b class='flag-5'>中注解</b>的作用

    如何通过注解来优化我们的Java代码

    Java注解可以说是我们编码过程中最常用的。本篇文章将给大家介绍Java注解的概念、作用以及如何使用注解来提升代码的可读性和灵活性,并介绍如
    的头像 发表于 09-30 11:39 329次阅读

    PCB刻制线圈怎么做到

    `如附图这种PCB刻制线圈是怎么做的,画得这么圆是怎么做到的?`
    发表于 06-13 11:07

    下图DCDC的动态调节电压是怎么做到的?

    请具体描述一下面的电路是怎么具体做到调压的?其中PWM_LOG输出PWM波形。是怎么做到具体动态调节的?感谢回答。
    发表于 11-09 17:57

    详细介绍了Java泛型、注解、并发编程

    介绍了Java泛型、注解、并发编程、数据传输与序列化、高效IO、容器集合、反射与类加载以及JVM重点知识线程、内存模型、JVM运行时内存、垃圾回收与算法、Java中四种引用类型、GC 分代收集算法
    发表于 08-20 06:09

    HarmonyOS注解的使用方法分享

    定义我们的注解自定义注解1、声明注解功能:检测类中是否有规范的get方法新建java libray的module,命名为annotation,创建
    发表于 03-28 14:04

    斩波型运放减少噪声 怎么做到的?

    翻译: TI信号链工程师 Tom Wang (王中南) 斩波型运放提供较低的失调电压,同时也极大地减少了1 / f(闪烁)噪声。它是怎么做到的?这篇短文就来讨论这个主题。
    发表于 04-08 04:04 1w次阅读
    斩波型运放减少噪声 <b class='flag-5'>怎么做到</b>的?

    分析java注解基本概念

    什么是注解(Annotation): Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解
    发表于 09-27 14:53 0次下载

    怎么做到快速修补板式喂料机轴头磨损

    怎么做到快速修补板式喂料机轴头磨损
    发表于 01-23 11:10 2次下载

    注解定义Bean及开发

    注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。
    发表于 08-02 10:26 321次阅读

    JAVA中注解怎么做到的(上)

    。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。那么你知道JDK什么是元注解吗?注解有哪些分类吗?以及注解Java中最本质究竟是什么东西,
    的头像 发表于 05-11 10:57 470次阅读

    3分钟纯Java注解搭个管理系统

    Erupt一个通用后台管理框架,据说有 超低代码量 、 零前端代码 、零 CURD操作 、无需建表 ,纯Java注解开发 等特色,号称三分钟就可以搭建一个完整的后台管理系统。
    的头像 发表于 07-28 11:27 421次阅读
    3分钟纯<b class='flag-5'>Java</b><b class='flag-5'>注解</b>搭个管理系统

    怎么做到EMC设计与产品设计同步?(上)

    怎么做到EMC设计与产品设计同步?|深圳比创达EMC(上)
    的头像 发表于 08-28 14:56 286次阅读
    <b class='flag-5'>怎么做到</b>EMC设计与产品设计同步?(上)

    怎么做到EMC设计与产品设计同步?(中)

    怎么做到EMC设计与产品设计同步?(中)相信不少人是有疑问的,今天深圳市比创达电子科技有限公司就跟大家解答一下!
    的头像 发表于 08-29 10:34 267次阅读

    怎么做到EMC设计与产品设计同步?(下)

    怎么做到EMC设计与产品设计同步?|深圳比创达EMC(下)
    的头像 发表于 08-30 10:44 242次阅读