注解(Annotation) 也叫元数据 是一种代码级别的说明
    它是JDK1.6及以后版本引入的一个特性 与类、接口、枚举是在同一个层次
    它可以声明在包、类、字段、方法、局部变量、方法参数等的前面
    用来对这些元素进行说明、注释
    作用:本来可能需要很多配置文件 需要很多逻辑才能实现的内容 就可以使用一个或者多个注解来替代
    这样就使得编程更加简洁 代码更加清晰
    原理:本质上就是一个继承自java.lang.annotation.Annotation的接口

    1. 注解的写法
      @XXX(一些信息)
      2. 注解放置在哪里
      类的上面 属性上面 方法上面 构造方法上面 参数前面
      3. 注解的作用
      3.1 用来充当注释的作用(仅仅是一个文件的说明) 比如 @Deprecated 表示过期了
      3.2 用来做代码的检测(验证) 比如 继承类 或 实现接口时 需重写方法 他会在方法上面写有@Override
      如果你的方法不是重写的方法 它会报错
      3.3 可以携带一些信息(内容) 文件和注解是经常会用到的
      (但是文件和代码不在一个地方 注解和代码在一个地方)
      4. Java中有一些人家写好的注解
      4.1 @Deprecated 用来说明方法是废弃的
      4.2 @Override 用来做代码的检测 检测此方法是否是一个重写
      4.3 @SuppressWarnings() 括号里的信息是String[] {“ “,” “} 如果只写一个信息可以不写大括号
      @SuppressWarnings(“unused”) 变量定义后未被使用 不想让系统报错
      @SuppressWarnings(“serial”) 类实现了序列化接口 不添加序列化ID号 不想让系统报错
      @SuppressWarnings(“rawtypes”) 集合没有定义泛型 不想让系统报错
      @SuppressWarnings(“deprecation”) 方法废弃后会有横线 这个可以让横线没有
      @SuppressWarnings(“unchecked”) 出现了泛型问题 可以不检测
      @SuppressWarnings(“all”) 包含了以上所有 都可以不检查(最好不使用)
      5. 注解中可以有成员 也可以不携带
      注解中的成员类型不能随意写 只能是如下类型
      5.1 基本数据类型
      5.2 String类型
      5.3 枚举类型enum
      5.4 注解类型
      5.5 数组类型[] 数组里的内容需要是上述四种类型
      如果注解只有一个成员 则成员名必须取名为value() 在使用时可以忽略成员名和赋值号 =
      6. 如何自己描述一个注解类型

    6.1 通过@interface来定义一个新的注解类型
    6.2 发现写法与注解非常相似(可以用接口的特点来记忆)
    可以描述 public static final 的属性 比较少见
    可以描述 public abstract 的方法 方法要求必须有返回值 返回值类型是上述五种
    6.3 自己定义的注解若想拿来使用 光定义还不够 还需要很多细致的说明(需利用Java提供好的注解来说明)
    元注解(也是注解 不是拿来使用的 是用来说明注解的)
    6.3.1 @Target() 即注解的作用域 描述当前注解可以放置在哪里写的
    括号里是一个数组 数组类型是ElementType类型(枚举)
    取值:
    ElementType.TYPE 放在类、接口上
    ElementType.CONSTRUCTOR 放在构造方法上
    ElementType.FIELD 放在属性(字段)上
    ElementType.METHOD 放在方法上
    ElementType.PACKAGE 放在包上
    ElementType.PARAMETER 参数声明
    ElementType.LOCAL VARIABLE 局部变量声明
    若不想写 ElementType. 可以在导包的时候麻烦一点 静态导入
    6.3.2 @Retention 描述当前注解的生命周期
    注解可以存在于三个位置 源代码文件 字节码文件 内存中执行
    源代码文件 ——-> 编译 ——-> 字节码文件 ——-> 加载 ——-> 内存中执行
    SOURCE CLASS RUNTIME
    @Retention(RetentionPolicy.RUNTIME) 最大的范围 就算在内存中也能找到注解(通过反射获取)
    @Retention(RetentionPolicy.CLASS) 编译时记录到class中 运行时丢弃
    @Retention(RetentionPolicy.SOURCE) 只在源码显示 编译时丢弃
    6.3.3 @Inherited 一个标识性的元注解 描述当前注解是否能被子类对象继承
    6.3.3 @Document 描述当前注解是否能被文档记录 即生成javadoc时会包含注解
    6.4 使用自己的注解
    6.4.1 在注解里面描述了一个方法 方法没有参数 但方法有返回值String 即String[] test();

    在使用注解时 注解让我们传参数
    这可以理解为 注解里的方法 将我们传递给它的参数 搬运走了 交给别人
    6.4.2 使用别人写好的注解不用写方法名 我们自己定义的注解必须写方法名才能传递参数
    如果我们定义的注解只有一个方法 方法名字叫value 在使用时就可以省略方法名 即String value();
    原本应为@MyAnnotation(test=”abc”) 现在为可以@MyAnnotation(“abc”)
    如果传递的参数是一个数组 数组内只有一个元素 可以省略{ }
    如果方法有两个以上 每个方法必须写名字 顺序不分先后

    1. @Target({ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. public @interface MyAnnotation {
    4. String[] value();
    5. //String[] value() default "abc";
    6. //此时注解可以不传参 默认传的参数是abc
    7. //不写default必须传参
    8. }
    9. public class Test {
    10. @MyAnnotation("abc")//注意注解后面不要加分号
    11. public String name;
    12. @MyAnnotation("abc")
    13. public void eat() {
    14. }
    15. }
    1. 如何解析注解内携带的信息(反射机制)
      1 获取类Class 比如 类名.class
      2 获取类中成员 类 属性 方法 构造方法
      3 获取注解对象 Annotation a = 成员.getAnnotation(注解类型.class);
      4 获取注解对象对应的类 Class aclass = a.getClass();
      5 获取注解类中的value()方法 Method am = aclass.getMethod(“value”);
      6 执行value()方法即可得到注解中的信息 am.invoke(a);
      注意value()方法是属于注解对象的

      1. public class Person {
      2. @MyAnnotation({"小兰","女","18"})
      3. private String name;
      4. @MyAnnotation({"小黑","男","17"})
      5. public void eat(){
      6. }
      7. }

      获取属性上的注解:

      1. try {
      2. //解析Person类中属性上面的注解信息 需要用到反射技术
      3. //1.获取Person对应的Class
      4. Class clazz = Person.class;
      5. //2.获取Person里的属性
      6. Field field = clazz.getDeclaredField("name");
      7. //3.通过field获取注解对象
      8. //方式一:正常的对象调用执行过程
      9. //Annotation a = field.getAnnotation(MyAnnotation.class);
      10. // 我们的注解之所以是注解 是通过元注解来描述的
      11. // 前面大的类型来接收 后面是一个小的类型 这里相当于是一个多态的效果
      12. // 故父类的引用指向子类的对象 是调不到里面独有的方法的
      13. //所以应该用
      14. // MyAnnotation ma = (MyAnnotation) field.getAnnotation(MyAnnotation.class);
      15. // //4.利用ma对象执行注解中的value方法 就帮我们把信息搬过来了 可以得到注解里的信息
      16. // String[] values = ma.value();
      17. // System.out.println(values[0]);
      18. //但是不是所有的方法都叫value 所以这个方式不太好
      19. //方式二:通过反射
      20. Annotation a = field.getAnnotation(MyAnnotation.class);
      21. //4.利用反射执行a中的value方法
      22. Class aClazz = a.getClass();//利用a对象获取它对应的class 即注解对应的类
      23. //5.通过aclazz获取里面的value方法
      24. Method aMethod = aClazz.getMethod("value");
      25. //6.执行value方法 获取传递的信息
      26. String[] values = (String[]) aMethod.invoke(a);
      27. System.out.println(values[2]);

      获取方法上的注解:

      1. try {
      2. //解析Person类中属性上面的注解信息 需要用到反射技术
      3. //1.获取Person对应的Class
      4. Class clazz = Person.class;
      5. //2.获取Person里的方法
      6. Method m = clazz.getMethod("eat");
      7. //3.获取方法上的注解对象
      8. Annotation a = m.getAnnotation(MyAnnotation.class);
      9. //4.获取注解对应的类
      10. Class aClass = a.getClass();
      11. //5.获取注解里的value方法
      12. Method myMethod = aClass.getMethod("value");
      13. //6.执行value方法 注意方法所属对象为a
      14. String[] values = (String[]) myMethod.invoke(a);
      15. System.out.println(values[0]);
      16. } catch (Exception e) {
      17. e.printStackTrace();
      18. }