04. 掀开注解的神秘面纱

注解

1、注解的概念

注解:说明程序得,给计算机看的java

注释:用文字描述程序,给程序员看的程序员

// 单行注释
/* 多行注释 */
/** 文档注释 */

注解的定义:api

​ 注解(Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及之后版本引入的一个特性,与类、接口、枚举是在同一个层次。它能够声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。数组

做用分类:ide

一、编写文档:经过代码里标识的注解生成文档【生成文档doc文档】spa

二、编译检查:经过代码里标识的注解让编译器可以实现基本的编译检查【Override】code

三、代码分析:经过代码里标识的注解对代码进行分析【使用反射】对象

2、JDK 预约义注解

@Override 检查方法是否继承父类或接口继承

@@Deprecated 该注解表示注释的内容过期接口

@@SuppressWarnings 压制警告

@SuppressWarnings("all")
public class AnnoDemo {
    @Override
    public String toString() {
        return "Demo01{}";
    }
    @Deprecated
    public void show(){
        //发现过期了,功能跟不上需求了
    }
    public void showNew(){
        //知足功能更增强大的方法
    }
    public void demo(){
        show(); //不推荐使用,但可使用
        showNew();
        Date date = new Date();
        date.getYear();//不推荐使用,但可使用
    }
}

3、自定义注解

格式

//元注解
public @interface MyAnno{
    //属性列表
}

反编译 javap AnnoName.class

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

}

注解的本质其实就是一个接口,继承Annotation父接口

/**
 * 注解的本质就是接口
 */
public @interface MyAnno {
    public String show();
}

属性,在接口中定义的抽象方法

public @interface MyAnno {
    String Show1();
    int show2();
    String[] show3();
    AnnoName show4();
    PersonEnum show5();
}

1. 返回结果必须是以下类型

一、基本数据类型

二、String 类型

三、枚举类型

四、注解

五、以上类型的数组

public @interface MyAnno {
    String show1();
    int show2();
    String[] show3();
    AnnoName show4();
    PersonEnum show5();
}

2. 属性赋值需注意点

默认值

若是定义的属性时,使用default关键字给属性默认初始值,能够在使用注解是不赋值

public @interface MyAnno {
    String name();
    int age() ;
}
public class Demo01 {
    @MyAnno(name="andy",age = 18)
    public void show(){
    }
}
public @interface MyAnno {
    String name();
    int age() default 18;
}
public class Demo {
    @MyAnno(name="andy")
    public void show(){
    }
}

value

若是只有一个属性须要赋值,并且该属性的名称是 value,那么在赋值时 value能够省略

public @interface MyAnno {
    String value();
}
public class Demo {
    @MyAnno("andy")
    public void show(){
    }
}

{}

数组赋值的时候,值使用 {} 包裹,若是数组中只有一个值,那么{}能够省略

public @interface MyAnno {
    String show1();
    String[] show2();//数组一个值的时候能够省略大括号
    AnnoName show3();
    PersonEnum show4();
}
public class Demo01 {
    @MyAnno(show1="Andy",show3 = @AnnoName,show4 = PersonEnum.P1,show2 = {"a","b"})
    public void show(){
    }
}

4、元注解

JDK 中给咱们提供的4个元注解

1. @Target

描述当前注解可以做用的位置

​ 一、ElementType.TYPE,能够做用在类上

​ 二、ElementType.METHOD,能够做用在方法上

​ 三、ElementType.FIELD,能够做用在成员变量上

@Target({ElementType.TYPE, ElementType.METHOD,ElementType.FIELD})
public @interface MyAnno {

}
@MyAnno
public class Worker {
    @MyAnno
    private String name;
    @MyAnno
    public void show(){
    }
}

2. @Retention

描述注解被保留到的阶段

SOURCE < CLASS < RUNTIME

​ 一、SOURCE,表示当前注解只在代码阶段有效

​ 二、CLASS,表示该注解会被保留到字节码阶段

​ 三、RUNTIME,表示该注解会被保留到运行阶段 JVM

//自定义的注解,通常用RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {

}

3. @Documented

描述注解是否被抽取到 JavaDoc api中

4. @@Inherited

描述注解是否能够被子类继承

5、自定义注解案例

public class Teacher {
    public void show(){
        System.out.println("Teacher show ....");
    }
}
public class Student {
    public void show(){
        System.out.println("student show ....");
    }
}
/**
 * 自定义注解
 *  该注解标明要执行哪一个类中哪一个方法
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InvokAnno {
    String className();
    String methodName();
}
@InvokAnno(className = "com.andy.anno.Student",methodName = "show")
public class MyMain {
    public static void main(String[] args) throws Exception {
        //获取类对象
        Class<MyMain> clazz = MyMain.class;
        //获取类对象中的注解
        InvokAnno annotation = clazz.getAnnotation(InvokAnno.class);
        /*
        注解本质是 接口 获取到的其实时接口的实现
        public class MyInvokAnno implements InvokAnno{
            String className(){
                return "com.andy.anno.student";
            }
            String methodName(){
                return "show";
            }
        }
         */
        //获取注解中对应的属性
        String className = annotation.className();
        String methodName = annotation.methodName();
        System.out.println(className+" "+methodName);
        //经过反射的方式实现接口的功能
        Class<?> aClass = Class.forName(className);
        Method show = aClass.getDeclaredMethod("show");
        Object o = aClass.newInstance();
        show.invoke(o);
    }
}
相关文章
相关标签/搜索