精华内容
下载资源
问答
  • java注解源码--注解基础知识
    万次阅读
    2017-12-29 10:52:35

    注解准备知识:看到一个注解的源码

    @Target 使用注解时的作用的目标

    ElementType.ANNOTATION_TYPE 可以【给一个注解进行注解】
    ElementType.CONSTRUCTOR     可以给构造方法进行注解
    ElementType.FIELD           可以给属性进行注解
    ElementType.LOCAL_VARIABLE  可以给局部变量进行注解
    ElementType.METHOD          可以给方法进行注解
    ElementType.PACKAGE         可以给一个包进行注解
    ElementType.PARAMETER       可以给一个方法内的参数进行注解
    ElementType.TYPE            可以给一个类型进行注解,比如类、接口、枚举

    @Retention 注解生效的作用域

    RetentionPolicy.SOURCE  注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 
    RetentionPolicy.CLASS   注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。 
    RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

    @Documented 这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去

    @Inherited 表明该注解如果注解了父类,那么子类就会继承这些注解(即使子类没有被任何注解)

    @Repeatable 表明该注解可以在同一目标上多次使用,就像可以贴多个标签

    @AliasFor 注解属性的别名 (给注解的这个属性赋值就等于给AliasFor的这个属性赋值)

    注解可以有多个属性,没有指明key的,会【默认给注解属性的value()赋值】

    更多相关内容
  • java注解原始代码弹簧框架1 在这个项目中,我使用注释和Java代码配置创建了Spring项目。 运行应用程序 步骤1.安装Tomcat服务器并将其与IDE连接 第2步。添加lib文件夹中的Jar文件- Right click on Main project -> ...
  • 无论是在JDK还是框架中,注解都是很重要的一部分,我们使用过很多注解,但是你有真正去了解过他的实现原理么?你有去自己写过注解么? 一、相关 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及...
  • java注解源码分析 javapro 1、ArrayList 分析 源码注释 2)常用方法示例 3)常见bug分析 2、NIO 内容 1)基础知识点 2)实例
  • 通过源码看 Java 注解本质

    千次阅读 2019-05-05 07:08:02
    说明 Class 中储存了注解的信息,我们打开源码看看是否是这样: 上图是 Class 类的继承关系。Class 直接实现了AnnotatedElement接口,我们关于注解的解析都定义在 AnnotatedElement 这个接口里面的,我们看看 ...

    文章图片可能不太清晰,清晰版本请移步到:http://mp.weixin.qq.com/s?__biz=MzIzMjYzODEzMw==&mid=2247483658&idx=1&sn=0a6d6bd62e8967d096b09d1fc4decf59&chksm=e89092d0dfe71bc6625ddd63e5816ee9eb6908f98f1b0568264751ddd2412a70abe414a619a4#rd

    说到注解,我们首先想到的可能是  Spring 的注解,或者自定义注解,其实Java本身也自定义了一些注解,Java 源码的注解是所有注解的基石,本文基于 Java 源码来看看这些基础注解,慢慢揭开注解的本质,看看注解到底是什么,以方便我们工作中使用好注解。

    如果用一句话来描述注解的话,我可能会说注解是一种元数据,主要作用是用来描述业务的。

    比如在工作中,我们常常定义一些日志切面注解,注解会定义在对外的接口上,来帮助我们自动的打印日志,这样我们就不需要在每个对外的接口实现里面每次都手动的打印日志了。

    Java 元数据注解解析

    Java基础注解,也叫做元数据注解,主要是用来描述一个注解是什么的,比如描述注解的生存阶段,注解的使用对象等等,通过下图目录我们可以看到元数据注解种类很多,但我们常用的一共 5 种,如下图中标红的:

    接下来我们简单的介绍下这 5 种注解,以方便我们在工作中使用它们。

     

    @Target

    源码里面的解释:

     

    可以简单理解成注解的使用对象是谁,目前使用对象的种类在 ElementType 类里面有定义,如下图( ElementType ):

     

    ElementType 的枚举元素的名称 在 Java 里面都有相同命名的 Java 文件,我的理解可能是为了统一,毕竟当我们在 @Target 注解上面说明了使用范围时,编译器是需要去检查的,这其中是需要一个映射关系的,这样命名可能就是一种设计的约定。

    @Target 注解我们是可以传数组,表示可以同时作用在多个对象上,源码如图:

     

    @Retention

    源码解释如下:

    Retention 为我们提供了注解的保留策略,比如说我们想自己写个自定义注解,用来实现静态扫描的功能,那么这个注解的保留策略选择 CLASS 就好了,如果我们的自定义注解是为了实现动态的监控的话,那么保留策略应该选择 RUNTIME,三种策略的解释上图中都有。

     

    @Inherited

    如果自定义注解上加了这个元数据的话,如果自定义注解被用到了类上,一旦这个类被继承,子类是可以继承父类自定义注解的一切信息的,举了一个例子:

    打印出的结果,显示的是父类 BaseTest 对 TestInheritedAnnotation 注解的赋值,说明注解的值已经被子类继承了,子类可以直接获取,如果  @Inherited 去掉的话,子类就不能够获取父类的注解信息了。

     

    @Repeatable

    注解一般都是不能重复打的,如果需要在方法或者类上重复的使用注解的话,就需要此元数据注解的帮助了,demo如下:

    通过新建另外一个注解,注解内必须有个方法名称是 value 的方法,来达到注解可以重复的书写的目的。

     

    注解的本质

    注解到底是什么。我们使用 javap 解析下注解,我们会发现注解其实是个接口,天然的继承了 Annotation 接口,我们在注解里面定义的值其实都是抽象方法,截图如下:

     

    注解本质是一个接口,接口是无法直接使用的,Java 通过默认生成一个子类的方式来使用注解,以方便储存和使用注解的值,我们通过启动 hsdb ,在 JVM 运行时 debug 发现,JVM 通过代理自动给注解生成一个实现类:

    ps:

    hsdb的启动命令是:

    java -classpath  /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/sa-jdi.jar sun.jvm.hotspot.HSDB

     

    我们工作中常常用的 Spring 的注解,常常会结合 Spring 的 AOP 特性,AOP 其实也是通过动态代理,来实现更多的功能,比如 Spring 的 @Transactional 注解,我们在 public 方法上写上这个注解,Spring 在初始化 bean 的时候,发现有这个注解,就会生成一个代理 bean ,运行过程主要是:在进入该方法前,初始化事务,然后进入方法,监听方法的运行状态,如果方法正常运行结束,则事务提交,检测到一切异常,则事务回滚,这里事务的提交和回滚都是通过 @Transactional 注解生成的切面代码来控制的。

     

    注解如何存贮和解析的:

    我们在前面的示例中使用过这样的代码:

    new ChildTest().getClass()

    .getAnnotation(TestInheritedAnnotation.class);

    我们直接Class中通过 getAnnotation 可以直接得到注解,

    说明 Class 中储存了注解的信息,我们打开源码看看是否是这样:

    上图是 Class 类的继承关系。Class 直接实现了AnnotatedElement接口,我们关于注解的解析都定义在 AnnotatedElement 这个接口里面的,我们看看 AnnotatedElement 接口还被那些子类实现:

    我们发现,所有可能会打上注解的地方,都继承了 AnnotatedElement 接口。

     

    AnnotatedElement 常用的几个方法如下图:

    getAnnotation和getAnnotationByType的区别主要在于

    getAnnotationByType能够得到重复的注解,比如你在一个方法上面写了两个相同的注解,那么这个就叫做重复的注解,这时候应该使用getAnnotationByType。

    我们通过 Class 文件的源码来看看是如何得到注解信息的,其余 Method , Field 的实现原理差不多。

    Class 维护了 annotationData 的数据结构,维护的源码如下:(while true 的作用是保证 CAS 算法的成功,一旦 CAS 失败后,会重新 createAnnotation,直到更新成功为止 )

    annotationData的数据结构为:AnnotatedElement 的所有行为,底层都是通过操作 annotationData 来实现的。

    通过 while(true) 的死循环保证 JVM 实例化类-> 解析注解信息时,一定是能够成功的,annotationData 本身又是 class 的一个属性,是 volatile transient 属性的,保证了一旦更改,所有线程都能够读取到,通过双重手段保证了 JVM 在初始化注解信息时一定是安全可靠的。

    更多的内容请扫描下面的二维码关注,方便交流,谢谢。

    个人公众号主要研究 Java、领域驱动设计、中台建设等方面,

     

    展开全文
  • java注解原始代码自定义Java注释 教程如何在以下位置创建自定义Java注释的源代码
  • JAVA 注解示例 详解

    2019-04-22 01:12:39
    NULL 博文链接:https://wangming2012.iteye.com/blog/1941123
  • java注解使用例子

    2019-04-08 01:33:46
    NULL 博文链接:https://smallbee.iteye.com/blog/1611962
  • java8流源码ls-注解 ls-annotation 是一个 java 字节码反编译器; 它提取并打印使用 java 注释的类、方法和字段的定义。 这个工具的目的是让带有相互依赖的注解的声明变得有意义,这种依赖的一个例子是 Spring Boot ...
  • 刚接触Java的时候就觉得注解是非常神奇,加之现在越来越多的开源项目采用注解的方式来实现,如Dagger2,ButterKnife。因此在空余时间好好研究了一下,本文将向你介绍一些自定义注解所需要的基础知识以及一个简单的...
  • 1 注解(Annotation) 官方解释:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过...JAVA注解有三

    1 注解(Annotation)

    官方解释:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
    Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

    通俗解释:注解就相当于一种规则,在某个类中使用了某个注解,就会触发这种规则。JAVA注解有三种类型,一种是内置注解(JAVA官方定义的注解可以直接用),一种是元注解(注解的注解,用来定义注解类时使用的注解),最后是自定义注解(自定义注解要用到元注解来定义)。元注解就是最底层的注解,用来定义其他注解。

    内置注解

    Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
    作用在代码的注解是
    @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
    @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
    @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
    作用在其他注解的注解(或者说 元注解)是:

    关键字用途
    allto suppress all warnings(抑制所有警告)
    boxingto suppress warnings relative to boxing/unboxing operations(要抑制与箱/非装箱操作相关的警告)
    castto suppress warnings relative to cast operations(为了抑制与强制转换操作相关的警告)
    dep-annto suppress warnings relative to deprecated annotation(要抑制相对于弃用注释的警告)
    deprecationto suppress warnings relative to deprecation(要抑制相对于弃用的警告)
    fallthroughto suppress warnings relative to missing breaks in switch statements(在switch语句中,抑制与缺失中断相关的警告)
    finallyto suppress warnings relative to finally block that don’t return(为了抑制警告,相对于最终阻止不返回的警告)
    hidingto suppress warnings relative to locals that hide variable(为了抑制本地隐藏变量的警告)
    incomplete-switchto suppress warnings relative to missing entries in a switch statement (enum case)(为了在switch语句(enum案例)中抑制相对于缺失条目的警告)
    nlsto suppress warnings relative to non-nls string literals(要抑制相对于非nls字符串字面量的警告)
    nullto suppress warnings relative to null analysis(为了抑制与null分析相关的警告)
    rawtypesto suppress warnings relative to un-specific types when using generics on class params(在类params上使用泛型时,要抑制相对于非特异性类型的警告)
    restrictionto suppress warnings relative to usage of discouraged or forbidden references(禁止使用警告或禁止引用的警告)
    serialto suppress warnings relative to missing serialVersionUID field for a serializable class(为了一个可串行化的类,为了抑制相对于缺失的serialVersionUID字段的警告)
    static-accesso suppress warnings relative to incorrect static access(o抑制与不正确的静态访问相关的警告)
    synthetic-accessto suppress warnings relative to unoptimized access from inner classes(相对于内部类的未优化访问,来抑制警告)
    uncheckedto suppress warnings relative to unchecked operations(相对于不受约束的操作,抑制警告)
    unqualified-field-accessto suppress warnings relative to field access unqualified(为了抑制与现场访问相关的警告)
    unusedto suppress warnings relative to unused code(抑制没有使用过代码的警告)

    元注解

    @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
    @Documented - 标记这些注解是否包含在用户文档中。
    @Target - 标记这个注解应该是哪种 Java 成员。
    @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
    @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

    定义注解

    通过几个案例来展示怎么定义注解
    案例一:

    //标记这些注解是否包含在用户文档中
    @Documented
    //用于描述域
    @Target({FIELD, TYPE})
    //运行时保留
    @Retention(RUNTIME)
    //自定义一个注解
    public @interface AnimalUser {
        //注解中包含两个变量,并且初始化
        int id() default 123;
    
        String name() default "小三";
    }
    
    //添加自定义的注解
    @AnimalUser
    //创建一个用户类
    public class User {
        //用户类中的两个属性
        private int id;
        private String name;
    
    }
    
    //创建测试类
    
    public class Demo {
    
        public static void main(String[] args) throws NoSuchFieldException {
            //反射一个USER对象
            var m = User.class;
            //输出对应字段内容
            System.out.println(m.getAnnotation(AnimalUser.class).name());
            System.out.println(m.getAnnotation(AnimalUser.class).id());
    
    
        }
    }
    

    案例二

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface AnimalUser {
        //注解中包含两个变量,并且初始化
        int id() default 123;
    
        String name() default "小三";
    }
    
    
    //创建一个用户类
    public class User {//添加自定义的注解
        @AnimalUser
        private String user;
    
    }
    
    //创建测试类
    
    public class Demo {
    
        public static void main(String[] args) throws NoSuchFieldException {
            //反射一个USER对象
            var m = User.class;
            //判断类USER中的注解是否含有对应的字段
            var a = m.getDeclaredField("user");
            //输出对应字段内容
            System.out.println(a.getAnnotation(AnimalUser.class).name());
            System.out.println(a.getAnnotation(AnimalUser.class).id());
    
    
        }
    }
    
    

    两个案例中的区别
    在这里插入图片描述

    展开全文
  • java注解原始代码安·多库根(AnnDocuGen) 准备 确保至少使用Sun / Oracle JDK版本6。 Maven 3也是必需的。 用法 mvn clean install 然后,参见example/target/generated-sources/annotations/annDocuGen 。
  • java 注解源码
  • java注解是java5引入的功能,我们能够经常看到,如@Override,但未必对其有深入的了解。了解这方面的知识有助于我们深入理解一些框架,下面就以模仿AndroidAnnotations中三个注解特性来详细说明。 注解布局文件,@...
  • 理解Java注解 注解就相当于对源代码打的标签,给代码打上标签和删除标签对源代码没有任何影响。有的人要说了,你尽几把瞎扯,没有影响,打这些标签干毛线呢?其实不是这些标签自己起了什么作用,而且外部工具通过...
  • java源码Java的UIMA注解类 uimaFIT.zip
  • 3、对spring aop认识模糊的,不清楚如何实现Java 自定义注解的 4、想spring aop 注解实现记录系统日志并入库等 二、能学到什么 1、收获可用源码 2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑...
  • 基于Spring boot + maven,以注解+AOP方式实现的java后端项目接口参数校验框架。迄今为止使用最简单、最容易理解的参数校验方案。博客地址:https://blog.csdn.net/weixin_42686388/article/details/104009771
  • java jdk8 源码 Java-source-code JDK源码包含个人学习时的理解与注解 可更好的理解JDK底层实现
  • Java注解

    2020-12-21 01:09:58
    Java源码中提取的所有注解 注解 版本 说明 @WebParam   表示方法的参数 @Oneway   表示为只有输入消息而没有输出消息的 Web Service 单向操作 @WebResult   表示方法的返回值 @HandlerChain   使...
  • java注解深入理解

    2019-04-11 01:08:23
    NULL 博文链接:https://thetopofqingshan.iteye.com/blog/1679435
  • 翻译java源码中注释 java源码翻译
  • Java注解精讲

    2021-06-17 09:12:18
    本课程详细介绍了Java中的注解机制,包括注解的定义和分类,注解的使用和自定义,注解的源码和架构分析; 本课程语言简单凝练,视频短小精悍,让你一次彻底搞懂Java注解
  • 注解java文件的源码PojoBuilder - Pojo Builders 的代码生成器 添加一名作者 项目主页: 关于 PojoBuilder Generator 是一个符合 Java 6 的注解处理器,它为 POJO(Plain Old Java Object)生成一个流畅的构建器...
  • 一、自定义注解格式、 二、注解本质分析、 三、注解属性及类型、 四、注解属性类型、 五、注解属性赋值简化操作、





    一、自定义注解格式



    分析 Java 中自带的 @Override 注解 , 源码如下 :

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    注解分为两部分 :

    ① 元注解 ;

    ② public @interface 注解名称 ;





    二、注解本质分析



    按照 public @interface 注解名称 格式 , 写出一个注解 , 编译该注解代码生成 Annotation.class 字节码文件 ;

    public @interface Annotation {
    }
    

    使用 javap 命令反编译Annotation.class 字节码文件 , 查看该注解的实际代码 ;

    反编译命令如下 :

    javap Annotation.class
    

    输出内容 :

    D:\002_Project\004_Java_Learn\Annotation\out\production\Annotation>javap Annotation.class
    Compiled from "Annotation.java"
    public interface Annotation extends java.lang.annotation.Annotation {
    }
    

    在这里插入图片描述


    注解的本质是一个 interface 接口 , 注解接口默认继承了 java.lang.annotation.Annotation 接口 ;

    public interface Annotation extends java.lang.annotation.Annotation {
    }
    




    三、注解属性及类型



    注解的本质是接口 , 接口中可以定义 常量方法 ;

    在注解中定义 接口方法 , 就是 注解的属性 ;

    为注解添加属性 : 接口中的方法都是抽象方法 , 其中 public abstract 可以省略 ;

    public @interface Annotation {
        public abstract String path();
    }
    

    注解属性使用格式 :

    @注解名称(属性名称 = 属性值)
    

    注解属性使用 : 在相关的代码上使用

        @Annotation(path = "")
        Student(String name, int age){
        }
    




    四、注解属性类型



    注解属性 ( 接口方法 ) 返回值类型要求 :

    基本数据类型 : byte , short , int , long , float , double , char , boolean ;

    字符串类型 : String ;

    枚举类型 : enum ;

    注解类型 ;

    以上类型的数组形式 ;

    注解属性返回值必须是以上的类型 , 不能设置其它类型返回值 , 否则会报错 ;


    注解中定义了属性 , 在使用注解时 , 需要 给 注解属性 赋值 ;

    定义 注解属性 时 , 可以 使用 default 关键字 指定属性默认值 , 下面代码中 , 制定 注解属性 intValue 值类型为 int 整型 , 默认值 88 ;

    int intValue() default 88;
    

    如果 注解属性 指定了默认值 , 在使用注解时 , 可以选择 不为该属性赋值 ( 此时使用默认属性值 ) , 也可以进行赋值 ( 指定一个新的属性值 ) ;

    如果 注解属性 没有指定默认值 , 则使用 注解 时 , 必须为其指定一个默认值 , 否则编译时报错 ;


    数组类型 的 注解属性 赋值 时 , 使用大括号进行赋值 , 大括号内是数组元素 , 如果只有一个属性 , 可以省略大括号 ,


    注解 声明示例 :

    public @interface Annotation {
        /**
         * 字符串类型
         * @return
         */
        String stringValue();
    
        /**
         * int 基本类型
         * @return
         */
        int intValue() default 88;
    
        /**
         * 枚举类型
         * @return
         */
        Number enumValue();
    
        /**
         * 注解类型
         * @return
         */
        Annotation2 annotationValue();
    
        /**
         * 字符串数组类型
         * @return
         */
        String[] stringArrayValue();
    }
    

    枚举类 :

    public enum Number {
        ONE, TWO, THREE
    }
    

    Annotation2 注解类 :

    public @interface Annotation2 {
    }
    

    注解使用示例 :

    /**
     * 注解生成文档
     *
     * @author hsl
     * @version  0.1
     * @since 1.5
     */
    public class Student {
        /**
         * 构造函数
         * @param name 参数一
         * @param age 参数二
         */
        @Annotation(
                stringValue = "tom",
                enumValue = Number.ONE,
                annotationValue = @Annotation2,
                stringArrayValue = {"tom", "jerry"})
        Student(String name, int age){
        }
    
        @SuppressWarnings("all")
        @Override
        public String toString() {
            return super.toString();
        }
    }
    

    代码分析 : 重点关注注解的使用 , 使用注解时 , 需要给 没有默认值 的 注解属性 赋值 , 格式为 注解属性名称 = 对应类型属性值 , 如果 注解属性 有默认值 , 则

    @Annotation(stringValue = "tom", enumValue = Number.ONE, stringArrayValue = {"tom", "jerry"})
    




    五、注解属性赋值简化操作



    如果 注解属性 名称是 value , 并且 注解中只有 1 1 1 个属性 , 那么在使用 注解 为 注解属性 赋值时 , 可以省略注解名称 , 直接传入 注解属性值 ;

    示例 : JDK 自带的 SuppressWarnings 注解 ,

    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    

    注解使用 : 使用 SuppressWarnings 注解时 , 直接传入 “all” 参数 , 省略了注解属性名称 ;

        @SuppressWarnings("all")
        @Override
        public String toString() {
            return super.toString();
        }
    

    满足两个条件 , 才能使用上述简化方式 ;

    展开全文
  • Java 注解

    千次阅读 2021-12-02 15:38:09
    Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 注解是元数据的一种形式,提供有关 于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。 注解声明 声明一个注解...
  • Java 注解介绍

    千次阅读 2021-04-22 04:30:03
    定义Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据(元数据 Metadata:描述数据的数据)。Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射...
  • 一、Java注解基础: 在Java中,一个自定义的注解起来是类似下面这样子的: @Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface Factory { String value() default ""; } 该注解用于...
  • 秒懂,Java 注解 (Annotation)你可以这样学

    万次阅读 多人点赞 2017-06-27 21:48:30
    文章开头先引入一处...Annotation 中文译过来就是注解、标释的意思,在 Java注解是一个很重要的知识点,但经常还是有点让新手不容易理解。 我个人认为,比较糟糕的技术文档主要特征之一就是:用专业名词来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 150,965
精华内容 60,386
关键字:

java注解的源码怎么看

java 订阅