注解

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

作用:
  编写文档:通过代码里标识的注解生成文档 --> 生成文档doc文档
  代码分析:通过代码里标识的注解对代码进行分析 --> 使用反射
  编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查 --> Override
为了代码简洁、利于扩展和维护。

JDK内置注解

@Override:检测被该注解标注的方法是否是继承自父类(或接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告
    1.deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告)==>该方法已经过时了
    2.unchecked:执行了未检查转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告。
    3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
    4.path:在类路径、源文件路径等中有不存在的路径时的警告; ==>FileNotFoundException
    5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
    6.finally:任何 finally 子句不能正常完成时的警告;
    7.all:关于以上所有情况的警告。


自定义注解
格式:

元注解
public @interface 注解名称{ 属性列表 }

  注解的本质是一个 接口 。还接口默认继承了 Annotation 接口。
  jvm运行时会自动帮我们创建它的实现类。
执行 javap 类名,进行反编译:

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

 

元注解
用于描述注解的注解

@Target:描述注解能过作用的位置  
ElementType的取值:
  TYPE:可以作用于类上
  METHOD:可以作用于方法上
  FIELD:可以作用于成员变量上

@Retention:被保留的阶段
  @Retention(RetentionPolicy.RUNTIME) --> 会保留到class字节码文件中,并被JVM读取到。运行时可以通过反射获得。
  SOURCE:注解仅存在于源码中,在class字节码文件中不包含。
  CLASS:默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得。
生命周期:SOURCE < CLASS < RUNTIME。
一般如果需要在运行时区动态获取注解信息,只能用RUNTIME。
如果要在编译时做一些预处理操作,比如生成一些辅助代码(如ButterKnife),用CLASS。
如果只是做一些检查性的操作,则可选用SOURCE。

@Documented:描述注解是否被抽取到api文档中

@Inherited:描述注解是否被子类继承

@Target的源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

ElemetType.java 源码

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,
    /** Method declaration */
    METHOD,
    /** Formal parameter declaration */
    PARAMETER,
    /** Constructor declaration */
    CONSTRUCTOR,
    /** Local variable declaration */
    LOCAL_VARIABLE,
    /** Annotation type declaration */
    ANNOTATION_TYPE,
    /** Package declaration */
    PACKAGE,
    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,
    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
TYPE,  接口、类、枚举、注解
FIELD,  字段,枚举常量
METHOD,  方法
PARAMETER,  方法参数
CONSTRUCTOR,  构造函数
LOCAL_VARIABLE,  局部变量
ANNOTATION_TYPE,  注解
PACKAGE,  包


自定义注解&属性定义
属性:注解中的抽象方法。
属性的返回值,即抽象方法的返回值:
  基本数据类型  
  枚举  
  注解  
  以上类型的数组
定义了属性,需要在使用时给属性赋值:
  1、如果定义属性时,用default 给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
    String name() default "payn";
  2、如果只有一个属性需要赋值,并属性的名称为value,则value可省略。
  3、数组赋值时,值使用{}包裹。如果数组中只有一个值,{}可省略。

自定义注解实现反射功能:
注解类 Pro:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();        //代表了一套规范
    String methodName();
    String name() default "payn";
}

Demo01

public class Demo01 {
    public void show(){
        System.out.println("demo01...show...");
    }
}

ReflectTest

@Pro(className = "com.itheima.anno01.Demo01",methodName = "show")
public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //前提:不改变任何该类的任何代码,可以创建任意类的对象,执行任意方法。
        //获取该类的字节码文件对象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;
        //获取上边的注解对象
        //其实就是在内存中生成了一个该注解接口的子类实现对象
        /*
            public class ProImpl implements Pro{
                public String className(){
                    return "cn.itcast.annotation.Demo1";
                }
                public String methodName(){
                    return "show";
                }
            }
         */
        Pro an = reflectTestClass.getAnnotation(Pro.class);//获取指定的注解
//        System.out.println(an);        
        //@com.itheima.anno01.Pro(className=com.itheima.anno01.Demo01, methodName=show)
        //获取注解对象中定义的抽象方法,获取返回值。
        String className = an.className();
        String methodName = an.methodName();
        
        //加载Demo01类进内存
        Class cls = Class.forName(className);
        Object obj = cls.newInstance();
        Method method = cls.getMethod(methodName);
        //执行Demo01中的show方法
        method.invoke(obj);
        
    }
}

 

posted @ 2019-03-27 10:57  payn  阅读(217)  评论(0)    收藏  举报