美文网首页
java 注解

java 注解

作者: sunny4handsome | 来源:发表于2017-12-10 16:03 被阅读0次

    本文介绍java中的注解,第一部分给出注解的基础介绍,第二部给出一个注解的应用实例。

    Java注解分为2个部分

    • 自定义注解
    • 元注解

    一、注解介绍

    1、Java 注解语法

    Modifiers @interface AnnotationName{
    element1 declaration;
    element2 declaration;
    }
    

    每一个元素的语法如下:

    type elementName();
    or
    type elementName() default value;
    

    2、举例

    public @interface BugReport{
    public int level() default 1;
    public String description;
    }
    

    3、元注解

    用注解其他注解
    java中定义的四种元注解

    • @Target(应用范围,class、method、field),
    • @Retention(注解的生命周期),
    • @Documented,
    • @Inherited

    二、元注解解释

    1、@Target(如果没有声明,则可以修饰任何的范围):

    @Target说明了Annotation所修饰的对象范围:Annotation可被用于packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
    作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

    取值(ElementType)有:

        1.CONSTRUCTOR:用于描述构造器
        2.FIELD:用于描述域
        3.LOCAL_VARIABLE:用于描述局部变量
        4.METHOD:用于描述方法
        5.PACKAGE:用于描述包
        6.PARAMETER:用于描述参数
        7.TYPE:用于描述类、接口(包括注解类型)或enum声明
    

    2、@Retention(如果没有声明,则默认为class级别):

    @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对Annotation的“生命周期”限制。

    作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

    取值(RetentionPoicy)有:

     
        1.SOURCE:在源文件中有效(即源文件保留)
        2.CLASS:在class文件中有效(即class保留)
        3.RUNTIME:在运行时有效(即运行时保留)
    

    3、@Documented:

    @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
    4、@Inherited:

    @Inherited元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

    注意:@Inheritedannotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

    当@Inheritedannotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inheritedannotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

    三、应用实例

    注解本身是没有声明作用的,只用通过java的反射,注解才有意义,实例作用如下:

    * 作用:一般公司中会用代码review的环节,这个写了一个工具,别人在看代码的时候
     *      如果发现的代码中的问题,直接添加注解,包括Bug的严重程度和错误信息
     * 1、BugReport 自定义注解,用于注解发现代码中的bug
     * 2、DemoBugReport 要review的代码
     */
    BugReport:注解定义
    @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface BugReport {
        public int level() default 1;//bug 严重级别
        public String description();//bug 信息描述
    }
    DemoBugReport:注解运用
    @BugReport(level=10,description="should use abstract classs")
    public class DemoBugReport {
        @BugReport(level=1,description="warning 1")
        public int value1;
        @BugReport(level=2,description="warning 2")
        public String value2;
        @BugReport(level=3,description="warning 3")
        public float value3;
        @BugReport(level=1,description="error 1")
        public void fun1(){ }
        @BugReport(level=1,description="error 2")
        public void fun2(){ }
        @BugReport(level=1,description="error 3")
        public void fun3(){ }
        @BugReport(level=1,description="4")
        public void fun4(){ }
        
    }
    ReviewLog:通过反射来生成Bug 报告
    public class ReviewLog {
        public static void main(String[] args) {
            Class c = DemoBugReport.class;
            Annotation[] classAnnoatoins = c.getAnnotations();
            System.out.println(c.getName()+" bug report");
            System.out.println();
            for(Annotation an:classAnnoatoins){
                if(an instanceof BugReport){
                    BugReport report = (BugReport)an;
                    System.out.println("bug level:"+report.level()+"\t"+"error info:"+report.description());
                }
            }
            System.out.println();
            System.out.println("field bug report");
            System.out.println();
            Field[] fs = c.getFields();
            for(Field f:fs){
                Annotation[] fieldAnnoations = f.getAnnotations();
                for(Annotation an:fieldAnnoations){
                    if(an instanceof BugReport){
                        BugReport report = (BugReport)an;
                        System.out.println(f.getName()+"\t"+"bug level:"+report.level()+"\t"+"error info:"+report.description());
                    }
                }
            }
            System.out.println();
            System.out.println("method bug report");
            System.out.println();
            Method[] ms = c.getMethods();
            for(Method m:ms){
                Annotation[] methodAnnoations = m.getAnnotations();
                for(Annotation an:methodAnnoations){
                    if(an instanceof BugReport){
                        BugReport report = (BugReport)an;
                        System.out.println(m.getName()+"\t"+"bug level:"+report.level()+"\t"+"error info:"+report.description());
                    }
                }
            }
        }
    }
    
    

    输出信息:

    com.sunny.annotation.DemoBugReport bug report
    
    bug level:10    error info:should use abstract classs
    
    field bug report
    
    value1  bug level:1 error info:warning 1
    value2  bug level:2 error info:warning 2
    value3  bug level:3 error info:warning 3
    
    method bug report
    
    fun1    bug level:1 error info:error 1
    fun2    bug level:1 error info:error 2
    fun3    bug level:1 error info:error 3
    fun4    bug level:1 error info:4
    

    四、备注

    经常会看到如下面的�注解

    @RequestMapping("hello")
    

    上面的注解的圆括号中是不带属性名称的,那是因为RequestMapping中有value这个字段,�java会特殊处理,不需要指定属性名也可以用,例如下面这样:

    public @interface MyAnnotation {
        String value();
    }
    

    就可以不带属性名称使用了:

    @Test("hello")
    public class Demo {
    
    }
    

    相关文章

      网友评论

          本文标题:java 注解

          本文链接:https://www.haomeiwen.com/subject/dlrvixtx.html