注解(Annotation)

注解(Annotation)

1. 概念

  • 代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。

2. 注解介绍

  • 定义注解:[修饰符] @interface 注解名{}

  • 注意事项:

    • 注解的本质是接口,默认继承了java.lang.annotation.Annotation

    • 注解只能包含属性,属性后面跟小括号,使用default 关键字给属性赋默认值。(公有的抽象方法)。

      • 返回类型 注解属性名称() [default 默认值];

    • 如果注解属性指定了默认值,那么使用的时候可以不指定属性的值,如果没有默认值,则使用的时候必须指定默认值。

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

    • 如果属性名是value,且只有一个属性,使用赋值时可以省略属性名,直接给属性值即可。

    • 注解的属性类型要求

      • 8种基本数据类型

      • String

      • enum

      • 注解类型

      • Class 类型

      • 以上类型的一维数组类型

  • 注解的使用

    • 注解中定义了属性,使用的时候需要给注解赋值

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

  • 常见注解:@Override、@Deprecated

    • 查看注解的源代码

  • package com.qf.annotation;

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    //指定 注解可以使用的范围。
    @Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnoation {

    // 注解中的属性。可以赋予默认值。
    int age() default 10;
    String name() default "tom";
    String[] names() default {"tom","jerry"};
    int value();

    }

    @interface MyAnno{

    }


    package com.qf.annotation;

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;

    /**
    * 注解:Annotation
    *
    * 概念:
    * 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
    * 它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
    * 总结:注解是一种特殊的类,用来给类中的元素进行说明和注释的。
    *
    * 作用分类:
    * ① 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
    * ②【 代码分析】:通过代码里标识的元数据对代码进行分析【使用反射】
    * ③【编译检查】:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
    *
    * 注解的分类
    * 1:【jdk的内置注解。】
    * 1:普通的注解
    * @Override、在编译期对该注解下面的方法进行编译期检查,该方法必须是重写父类的方法。
    * @Deprecated、用来标识下面的内容是过时的。不建议使用的。
    * @SuppressWarnings("all")、用来在编译期进行警告压制,一般传入一个参数"all" 代表所有的内容。
    *
    * 思考:
    * 不同的注解可以使用的场景是不同的,如何定义注解使用的场景。
    * 通过元注解 @Target 定义注解的使用的场景。
    * 2:元注解
    * 1:定义注解的注解,用来给注解添加属性和限制的。
    * 2:自定义注解。
    * 1:语法:
    * 权限修饰符 @interface 注解名{
    * //带返回值的抽象方法。
    * }
    * 2:通过反编译,得知,注解本质上就是一种接口,默认继承了 java.lang.annotation 接口。
    *
    * 3:注解的特点:
    * 1:注解中的(抽象方法-->【属性】),必须有返回值类型。
    * 返回值的类型允许的内容:
    * 1:八种基本数据类型。
    * 2:String 类型
    * 3:枚举类型
    * 4:注解类型
    * 5:Class 类型
    * 6: 上述类型的数组类型。
    *
    *
    * 4:元注解
    * 定义注解的注解。对注解类型进行解释说明的。 在注解的上面定义使用。
    * 元注解的定义:@Target(ElementType.ANNOTATION_TYPE)限定了元注解只能在注解上使用。
    * 1:@Target 限定注解可以使用的场景。
    *
    * ElementType 枚举中指定的:
       TYPE, 类,
       FIELD, 字段
       METHOD, 方法。
       PARAMETER,
       CONSTRUCTOR,
       LOCAL_VARIABLE,
       ANNOTATION_TYPE,
       PACKAGE,
       TYPE_PARAMETER,
       TYPE_USE
       
       2:@Retention 指定注解的内容保留在代码中的级别
        RetentionPolicy 枚举中定义了保留级别。
      SOURCE, 注解只保留在源代码中。
      CLASS, 注解保留到字节码中。
      【RUNTIME,运行时可以读取注解的内容,一般使用这个。】
     
     
      3:@Documented
      注解的内容可以生成到 javadoc 的文档中。
     
      4:@Inherited
      可以被子类继承注解。
     
      5:@Repeatable    
      用于声明标记的注解为可重复类型注解,可以在同一个地方多次使用。
     
     
    总结:
    1:将一些外部的数据能够保留到和运行期,参与程序的执行。
    2:给代码中的一些内容添加标识。
    *
    */

    //没有任何属性的注解。
    @MyAnno
    public class TestAnnotation {

    // 只对注解中的没有默认值的属性赋值。
    @MyAnnoation(value=10)
    public static void main(String[] args) {
    }

    // 对注解中的所有的属性赋值。
    @MyAnnoation(value=10,age=10,name="jack",names={"bruce","black"})
    void test(){};

    // 对注解中的所有的属性赋值。如果数组只是一个元素,可以省略大括号。
    @MyAnnoation(value=10,name="jack",names="bruce")
    void test1(){};

    // 对注解中的所有的属性赋值。如果只有一个value 属性,那么可以省略 value,。直接写值。
    @MyAnnoation(100)
    void test2(){};

    }

    @SuppressWarnings("all")
    class A{
    private int i;
    @Deprecated
    void test(){}
    private void test1(){}
    }

    class B extends A{

    private int i;
    @Override
    void test() {
    super.test();
    }
    }
  •  

3. 元注解

  • 所谓元注解,其主要作用就是负责注解其他注解,为其他注解提供了相关的解释说明。

  • @Target 用于指定注解的使用范围 ElementType.TYPE:类、接口、注解、枚举 ElementType.FIELD:字段、枚举常量 ElementType.METHOD:方法 ElementType.PARAMETER:形式参数 ElementType.CONSTRUCTOR:构造方法 ElementType.LOCAL_VARIABLE:局部变量 ElementType.ANNOTATION_TYPE:注解 ElementType.PACKAGE:包

  • @Retention 用于指定注解的保留策略 RetentionPolicy.SOURCE:注解只保留在源码中,在编译时会被编译器丢弃。 RetentionPolicy.CLASS:(默认的保留策略) 注解会被保留在Class文件中,但不会被加载到虚拟机中,运行时无法获得。 RetentionPolicy.RUNTIME:注解会被保留在Class文件中,且会被加载到虚拟机中,可以在运行时获得。

  • @Documented 用于将注解包含在javadoc中

    默认情况下,javadoc是不包括注解的,但如果使用了@Documented注解,则相关注解类型信息会被包含在生成的文档中

  • @Inherited 用于指明父类注解会被子类继承得到

  • @Repeatable 用于声明标记的注解为可重复类型注解,可以在同一个地方多次使用。

4. 应用

  • 通过反射技术获取注解的内容,决定如何去使用类。

  • package com.qf.annotation;

    import java.io.InputStream;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.reflect.Method;
    import java.util.Properties;

    import com.qf.test.Test;

    public class TestAnnoDemo1 {
    public static void main(String[] args) throws Exception {
    test2();
    }

    // 使用注解实现功能。替代配置文件
    @ConfigAnno(className="com.qf.annotation.MyClass",methodName="show1")
    private static void test2()throws Exception {
    // 通过反射读取注解的信息。
    // 获取注解作用的对象。test2 方法。
    Class<TestAnnoDemo1> clazz = TestAnnoDemo1.class;
    Method method = clazz.getDeclaredMethod("test2");

    // 获取作用对象上使用的指定注解的对象。
    ConfigAnno configAnno = method.getAnnotation(ConfigAnno.class);

    // 获取注解对象的属性值。
    String className = configAnno.className();
    String methodName = configAnno.methodName();

    // 通过类名和 方法名 得到 Class 和 Method
    Class<?> clazz1 = Class.forName(className);
    Object instance = clazz1.newInstance();

    Method method2 = clazz1.getDeclaredMethod(methodName);
    method2.invoke(instance);

    }

    // 通过配置文件实现的创建任意类对象,并调用任意方法功能。
    private static void test1() throws Exception {
    // 读取配置文件。
    InputStream is = Test.class.getResourceAsStream("config.ini");

    Properties prop = new Properties();
    prop.load(is);

    // 获取类名,并创建对象。
    String className = prop.getProperty("className");
    Class<?> clazz = Class.forName(className);
    Object instance = clazz.newInstance();

    // 获取方法名,并根据名字获取方法对象。并调用方法
    String methodName = prop.getProperty("method");
    Method method = clazz.getDeclaredMethod(methodName);
    method.invoke(instance);
    }

    }

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface ConfigAnno{
    String className();
    String methodName();
    }

    class MyClass{
    void show(){
    System.out.println("show");
    }
    void show1(){
    System.out.println("show1");
    }
    }
  • package com.qf.annotation;

    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.reflect.Method;

    /**
    * 利用注解,实现检测某个类中的某些方法执行的时候是否会出现异常。
    *
    */
    public class TestCheckException {

    @SuppressWarnings("resource")
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, IOException {
    // 获取所有添加了 @CheckAnnotation 注解的方法对象。

    Class<CheckClass> clazz = CheckClass.class;

    CheckClass instance = clazz.newInstance();

    BufferedWriter bw = new BufferedWriter(new FileWriter("./log.txt"));

    // 获取所有的方法
    Method[] methods = clazz.getDeclaredMethods();
    // 遍历方法,分析那个方法上面 有指定的注解
    for (int i = 0; i < methods.length; i++) {
    Method method = methods[i];

    // 判断method 对象上是否还有指定的注解。有 true。
    if(method.isAnnotationPresent(CheckAnnotation.class)){
    try {
    method.invoke(instance);
    } catch (Exception e) {
    // e.printStackTrace();
    // 将检测的结果输出到指定的文本中。
    bw.write("产生异常的方法:"+method.getName());
    bw.newLine();
    bw.write("异常的类型:"+e.getClass().getSimpleName());
    bw.newLine();
    bw.write("异常的原因:"+e.getCause().getMessage());
    bw.newLine();
    bw.write("********************************************");
    bw.newLine();
    bw.flush();
    }
    }
    }

    bw.close();


    }

    }

    //被检测的类。
    class CheckClass{

    @CheckAnnotation
    void test1(){
    System.out.println("test1");
    System.out.println(1/0);
    }
    void test2(){
    System.out.println("test2");
    }
    @CheckAnnotation
    void test3(){
    System.out.println("test3");
    }
    @CheckAnnotation
    void test4(){
    System.out.println("test4");
    System.out.println(1/0);
    }

    void show(){}

    }

    //定义用于检测方法执行是否会出现异常的注解
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface CheckAnnotation{
    }
  •  

posted @   ITboy搬砖人  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示