注解

mac2026-08-24  0

注解

1 注解概述

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

编写文档:通过代码里标识的注解生成文档【例如,生成文档doc文档】代码分析:通过代码里标识的注解对代码进行分析【例如,注解的反射】编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【例如,Override】

常见注解

@author:用来标识作者名

@version:用于标识对象的版本号,适用范围:文件、类、方法。

@Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。

2 自定义注解

定义格式

元注解 public @interface 注解名称{ 属性列表; } 注解本质上就是一个接口,该接口默认继承Annotation接口 public interface MyAnno extends java.lang.annotation.Annotation {}

注解的属性

属性的作用

可以让用户在使用注解时传递参数,让注解的功能更加强大。

属性的格式

格式1:数据类型 属性名();格式2:数据类型 属性名() default 默认值;

属性定义示例

public @interface Student { String name(); // 姓名 int age() default 18; // 年龄 String gender() default "男"; // 性别 } // 该注解就有了三个属性:name,age,gender

属性适用的数据类型

八种基本数据类型(int,float,boolean,byte,double,char,long,short)String类型,Class类型,枚举类型,注解类型以上所有类型的一维数组

3 使用自定义注解

在程序中使用(解析)注解的步骤(获取注解中定义的属性值):

获取注解定义的位置的对象 (Class,Method,Field)

获取指定的注解 getAnnotation(Class)

调用注解中的抽象方法获取配置的属性值

定义注解

定义一个注解:Book

包含属性:String value() 书名包含属性:double price() 价格,默认值为 100包含属性:String[] authors() 多位作者

代码实现

public @interface Book { // 书名 String value(); // 价格 double price() default 100; // 多位作者 String[] authors(); }

使用注解

定义类在成员方法上使用Book注解 /** * @author itheima * @version 1.0 */ public class BookShelf { @Book(value = "西游记",price = 998,authors = {"吴承恩","白求恩"}) public void showBook(){ } } 使用注意事项 如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。如果属性没有默认值,那么在使用注解时一定要给属性赋值。

特殊属性value

当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给属性值,无论value是单值元素还是数组类型。 // 定义注解Book public @interface Book { // 书名 String value(); } // 使用注解Book public class BookShelf { @Book("西游记") public void showBook(){ } }public class BookShelf { @Book(value="西游记") public void showBook(){ } } 如果注解中除了value属性还有其他属性,且至少有一个属性没有默认值,则在使用注解给属性赋值时,value属性名不能省略。 // 定义注解Book public @interface Book { // 书名 String value(); // 价格 double price() default 100; // 多位作者 String[] authors(); } // 使用Book注解:正确方式 @Book(value="红楼梦",authors = "曹雪芹") public class BookShelf { // 使用Book注解:正确方式 @Book(value="西游记",authors = {"吴承恩","白求恩"}) public void showBook(){ } } // 使用Book注解:错误方式 public class BookShelf { @Book("西游记",authors = {"吴承恩","白求恩"}) public void showBook(){ } } // 此时value属性名不能省略了。

4 注解之元注解

默认情况下,注解可以用在任何地方,比如类,成员方法,构造方法,成员变量等地方。如果要限制注解的使用位置怎么办?那就要学习一个新的知识点:元注解。

@Target@Retention

元注解之@Target

作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用。 可选的参数值在枚举类ElemenetType中包括:

TYPE: 用在类,接口上 FIELD:用在成员变量上 METHOD: 用在方法上 PARAMETER:用在参数上 CONSTRUCTOR:用在构造方法上 LOCAL_VARIABLE:用在局部变量上

元注解之@Retention

作用:定义该注解的生命周期(有效范围)。

可选的参数值在枚举类型RetentionPolicy中包括

SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。 CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。 RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。

元注解使用示例

@Target({ElementType.METHOD,ElementType.TYPE}) @interface Stu{ String name(); } // 类 @Stu(name="jack") public class AnnotationDemo02 { // 成员变量 @Stu(name = "lily") // 编译失败 private String gender; // 成员方法 @Stu(name="rose") public void test(){ } // 构造方法 @Stu(name="lucy") // 编译失败 public AnnotationDemo02(){} }

5 注解解析

什么是注解解析

通过Java技术获取注解数据的过程则称为注解解析。

与注解解析相关的接口

Anontation:所有注解类型的公共接口,类似所有类的父类是Object。AnnotatedElement:定义了与注解解析相关的方法,常用方法以下四个: boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有指定的注解,有则返回true,否则返回false。 T getAnnotation(Class annotationClass); 获得当前对象上指定的注解对象。 Annotation[] getAnnotations(); 获得当前对象及其从父类上继承的所有的注解对象。 Annotation[] getDeclaredAnnotations();获得当前对象上所有的注解对象,不包括父类的。

获取注解数据的原理

注解作用在那个成员上,就通过反射获得该成员的对象来得到它的注解。

如注解作用在方法上,就通过方法(Method)对象得到它的注解 // 得到方法对象 Method method = clazz.getDeclaredMethod("方法名"); // 根据注解名得到方法上的注解对象 Book book = method.getAnnotation(Book.class); 如注解作用在类上,就通过Class对象得到它的注解 // 获得Class对象 Class c = 类名.class; // 根据注解的Class获得使用在类上的注解对象 Book book = c.getAnnotation(Book.class);

使用反射获取注解的数据

需求说明

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

代码实现

注解Book

@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Book { // 书名 String value(); // 价格 double price() default 100; // 作者 String[] authors(); }

BookStore类

@Book(value = "红楼梦",authors = "曹雪芹",price = 998) public class BookStore { @Book(value = "西游记",authors = "吴承恩") public void buyBook(){ } }

TestAnnotation类

public class TestAnnotation { public static void main(String[] args) throws Exception{ System.out.println("---------获取类上注解的数据----------"); test01(); System.out.println("---------获取成员方法上注解的数据----------"); test02(); } /** * 获取BookStore类上使用的Book注解数据 */ public static void test01(){ // 获得BookStore类对应的Class对象 Class c = BookStore.class; // 判断BookStore类是否使用了Book注解 if(c.isAnnotationPresent(Book.class)) { // 根据注解Class对象获取注解对象 Book book = (Book) c.getAnnotation(Book.class); // 输出book注解属性值 System.out.println("书名:" + book.value()); System.out.println("价格:" + book.price()); System.out.println("作者:" + Arrays.toString(book.authors())); } } /** * 获取BookStore类成员方法buyBook使用的Book注解数据 */ public static void test02() throws Exception{ // 获得BookStore类对应的Class对象 Class c = BookStore.class; // 获得成员方法buyBook对应的Method对象 Method m = c.getMethod("buyBook"); // 判断成员方法buyBook上是否使用了Book注解 if(m.isAnnotationPresent(Book.class)) { // 根据注解Class对象获取注解对象 Book book = (Book) m.getAnnotation(Book.class); // 输出book注解属性值 System.out.println("书名:" + book.value()); System.out.println("价格:" + book.price()); System.out.println("作者:" + Arrays.toString(book.authors())); } } }

输出结果:

6 注解案例

案例说明

模拟Junit测试的@Test

案例分析

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

案例代码

注解MyTest

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

目标类MyTestDemo

public class MyTestDemo { @MyTest public void test01(){ System.out.println("test01"); } public void test02(){ System.out.println("test02"); } @MyTest public void test03(){ System.out.println("test03"); } }

调用类TestMyTest

public class TestMyTest { public static void main(String[] args) throws Exception{ // 获得MyTestDemo类Class对象 Class c = MyTestDemo.class; // 获得所有的成员方法对象 Method[] methods = c.getMethods(); // 创建MyTestDemo类对象 Object obj = c.newInstance(); // 遍历数组 for (Method m:methods) { // 判断方法m上是否使用注解MyTest if(m.isAnnotationPresent(MyTest.class)){ // 执行方法m m.invoke(obj); } } } } 输出结果:
最新回复(0)