Top

注解

1 注解的概述

1.1 注解的概念

  • 注解是JDK1.5的新特性。
  • 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
  • 标记(注解)可以加在包,类,字段,方法,方法参数以及局部变量上。
  • 注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。

    注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无何种 标记,看你的程序有什么标记,就去干相应的事,标记可以加在包、类,属性、方法,方法的参数以及局部变量上。

1.2 注解的作用

注解的作用就是给程序带入参数。

以下几个常用操作中都使用到了注解:

  1. 生成帮助文档@author和@version

    • @author:用来标识作者姓名。
    • @version:用于标识对象的版本号,适用范围:文件、类、方法。

      • 使用@author和@version注解就是告诉Javadoc工具在生成帮助文档时把作者姓名和版本号也标记在文档中。如下图:

1566448263760

  1. 编译检查@Override

    • @Override:用来修饰方法声明。

      • 用来告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。如下图

1566448286356

  1. 框架的配置(框架=代码+配置)

    • 具体使用请关注框架课程的内容的学习。

1.3 常见注解

  1. @author:用来标识作者名,eclipse开发工具默认的是系统用户名。
  2. @version:用于标识对象的版本号,适用范围:文件、类、方法。
  3. @Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。

2 自定义注解

2.1 定义格式

public @interface 注解名{

}
如:定义一个名为Student的注解
public @interface Student {

} 

2.2 注解的属性

  1. 属性的格式

    • 格式1:数据类型 属性名();
    • 格式2:数据类型 属性名() default 默认值;
  2. 属性定义示例
   // 姓名
   String name();
   // 年龄
   int age() default 18;
   // 爱好
   String[] hobby();
  1. 属性适用的数据类型
   * 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
   * String,Class,注解类型,枚举类
   * 以上类型的数组形式

3 使用自定义注解

3.1 定义和注解

  1. 定义一个注解:Book

    • 包含属性:String value() 书名
    • 包含属性:double price() 价格,默认值为 100
    • 包含属性:String[] authors() 多位作者
  2. 代码实现
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
    String value();
    double price() default 100;
    String[] authros();
}

3.2 使用注解

  1. 定义类在成员方法上使用Book注解
  1. 使用注意事项

    • 如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
    • 如果属性没有默认值,那么在使用注解时一定要给属性赋值。

3.3 特殊属性value

/**
    特殊属性value
        * 如果注解中只有一个属性且名字叫value,则在使用该注解时可以直接给该属性赋值,而不需要给出属性名。
        * 如果注解中除了value属性之外还有其他属性且只要有一个属性没有默认值,则在给属性赋值时
            value属性名也不能省略了。
    小结:如果注解中只有一个属性时,一般都会将该属性名命名为value
 */
@interface TestA{
   String[] value();
   int age() default 100;
   String name();
}

@interface TestB{
    String name();
}

@TestB(name = "zzz")
@TestA(name = "yyy",value = {"xxx","xxx"})
public class AnnotationDemo02 {

}

4 注解之元注解

元注解概述
    * Java官方提供的注解
    * 用来定义注解的注解
    * 任何官方提供的非元注解的定义都使用到了元注解。

常用的元注解
    * @Target
        * 作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
        * 可使用的值定义在ElementType枚举类中,常用值如下
            TYPE,类,接口
            FIELD, 成员变量
            METHOD, 成员方法
            PARAMETER, 方法参数
            CONSTRUCTOR, 构造方法
            LOCAL_VARIABLE, 局部变量

    * @Retention
        * 作用:用来标识注解的生命周期(有效范围)
        * 可使用的值定义在RetentionPolicy枚举类中,常用值如下
            * SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
            * CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
            * RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段

5 注解解析

  什么是注解解析
        * 使用Java技术获得注解上数据的过程则称为注解解析。
    与注解解析相关的接口
        * Annotation: 注解类,该类是所有注解的父类。
        * AnnotatedElement:该接口定义了与注解解析相关的方法
             T getAnnotation(Class<T> annotationClass) 根据注解类型获得对应注解对象
             Annotation[]    getAnnotations()
                * 获得当前对象上使用的所有注解,返回注解数组,包含父类继承的
             Annotation[]    getDeclaredAnnotations()
                * 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
             boolean    isAnnotationPresent(Class<Annotation> annotationClass)
                * 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

        获取注解数据的原理
            * 注解作用在哪个成员上就会得该成员对应的对象来获得注解
                * 比如注解作用成员方法,则要获得该成员方法对应的Method对象
                * 比如注解作用在类上,则要该类的Class对象
                * 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
            * Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口

5.1 需求说明

  1. 定义注解Book,要求如下:

    • 包含属性:String value() 书名
    • 包含属性:double price() 价格,默认值为 100
    • 包含属性:String[] authors() 多位作者
    • 限制注解使用的位置:类和成员方法上
    • 指定注解的有效范围:RUNTIME
  2. 定义BookStore类,在类和成员方法上使用Book注解
  3. 定义TestAnnotation测试类获取Book注解上的数据

5.2 代码实现

  1. 注解Book
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
    String value();
    double price() default 100;
    String[] authros();
}
  1. BookShelf类
@Book(value = "红楼梦",authros = {"曹雪芹"})
public class BookShelf  {

    @Book(value = "西游记",authros = {"吴承恩","白求恩"},price = 200)
    public void showBook(){

    }
}
  1. TestAnnotation类
/**
    什么是注解解析
        * 使用Java技术获得注解上数据的过程则称为注解解析。
    与注解解析相关的接口
        * Annotation: 注解类,该类是所有注解的父类。
        * AnnotatedElement:该接口定义了与注解解析相关的方法
             T getAnnotation(Class<T> annotationClass) 根据注解类型获得对应注解对象
             Annotation[]    getAnnotations()
                * 获得当前对象上使用的所有注解,返回注解数组,包含父类继承的
             Annotation[]    getDeclaredAnnotations()
                * 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
             boolean    isAnnotationPresent(Class<Annotation> annotationClass)
                * 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

        获取注解数据的原理
            * 注解作用在哪个成员上就会得该成员对应的对象来获得注解
                * 比如注解作用成员方法,则要获得该成员方法对应的Method对象
                * 比如注解作用在类上,则要该类的Class对象
                * 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
            * Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口
 */
public class AnnotationDemo04 {
    /*
        获得类上使用的注解数据
     */
    @Test
    public void test02() throws Exception {
        // 获得Class对象
        Class c = BookShelf.class;
        // 判断类上是否使用Book注解
        if(c.isAnnotationPresent(Book.class)){
            // 根据注解的Class对象获得对应的注解对象
            Book annotation = (Book) c.getAnnotation(Book.class);
            // 获得书名
            System.out.println(annotation.value());
            // 获得作者
            System.out.println(Arrays.toString(annotation.authros()));
            // 获得价格
            System.out.println(annotation.price());
        }
        // 获得当前对象上使用的所有注解,返回注解数组
        // Annotation[] annotations = c.getAnnotations();
        Annotation[] annotations = c.getDeclaredAnnotations();
        System.out.println(Arrays.toString(annotations));
    }

    /*
       获得成员方法上注解的数据
    */
    @Test
    public void test01() throws Exception {
        // 获得Class对象
        Class c = BookShelf.class;
        // 获得成员方法对应的Method对象
        Method m = c.getMethod("showBook");
        // 根据注解的Class对象获得对应的注解对象
        Book annotation = m.getAnnotation(Book.class);
        // 获得书名
        System.out.println(annotation.value());
        // 获得作者
        System.out.println(Arrays.toString(annotation.authros()));
        // 获得价格
        System.out.println(annotation.price());
    }
}

6 注解案例

6.1 案例说明

  • 模拟Junit测试的@Test

6.2 案例分析

  1. 模拟Junit测试的注释@Test,首先需要编写自定义注解@MyTest,并添加元注解,保证自定义注解只能修饰方法,且在运行时可以获得。
  2. 然后编写目标类(测试类),然后给目标方法(测试方法)使用 @MyTest注解,编写三个方法,其中两个加上@MyTest注解。
  3. 最后编写调用类,使用main方法调用目标类,模拟Junit的运行,只要有@MyTest注释的方法都会运行。

6.3 案例代码

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {

}

public class TestMyTest {

    @MyTest
    public void tests01(){
        System.out.println("test01");
    }


    public void tests02(){
        System.out.println("test02");
    }

    @MyTest
    public void tests03(){
        System.out.println("test03");
    }
}

/**
 * @author pkxing
 * @version 1.0
 * @Package com.itheima
 * @date 2018/6/23  下午9:10
 */
public class AnnotationDemo05 {
    public static void main(String[] args) throws Exception {
        // 获得Class对象
        Class c = TestMyTest.class;
        Object obj = c.newInstance();
        // 获得所有成员方法
        Method[] methods = c.getMethods();
        for(Method m:methods){
            // 判断m方法是否使用了MyTest注解
            if(m.isAnnotationPresent(MyTest.class)){
                // 调用方法
                m.invoke(obj);
            }
        }
    }
}

标签: none

版权类型: 原创

版权声明: 转载时请注明出处和链接地址

文章链接: https://smallchild.cn/8.html

添加新评论