注解Annotation的使用 深入理解Java中的注解 自定义注解 元注解
注解
1. 概念
(1) 注解:用于说明程序,给计算机看的,JDK1.5之后的新特性
使用方式:@注解名称
(2) 注释:用文字描述程序,给编码人员看的
2. 作用
(1) 编写文档
将代码里标识的注解生成doc文档:
① 创建一个类
/**
* 注解javadoc演示
* @author 周杰伦 表示此类(文档)作者
* @version 1.0 表示此类(文档)的版本
* @since 1.8 表示从JDK1.8之后可以使用此类
*/
public class AnnoDemo1 {
/**
* 计算两数的和
* @param a 整数
* @param b 整数
* @return 两数的和
*/
public int add(int a, int b ){
return a + b;
}
}
② 对此java文件使用javadoc指令
③ 打开后的doc文档
(2) 代码分析:使用反射通过代码中的注解对代码进行分析
(3) 编译检查:通过注解实现编译检查,如@Override
3. 自定义注解
(1) 格式
public @interface 注解名称 {
// 属性列表;
}
(2) 本质
注解本质上就是一个默认继承Annotation接口的接口,如下:
public interface 自定义注解 extends java.lang.annotation.Annotation {}
(3) 注解中的属性
注解的属性即接口中的抽象方法
要求:
① 属性的返回值类型:
i. 基本数据类型
ii. 字符串类型String
iii. 枚举
iiii. 注解
iiiii. 以上类型的数组
注意:其他的类型如类类型、void都不可以
② 定义了属性之后,使用时需要给属性赋值
// 自定义注解
public @interface MyAnno {
//以下均为省略了abstract关键字的抽象方法
Person per(); //枚举类型,其中有P1,P2
MyAnno2 anno2(); // 注解类型,定义另一个注解MyAnno2
String[] strs(); // 数组类型
//使用default关键字给属性赋值,表示默认初始值,
//则使用注解时,可以不给此属性赋值,而使用默认值
int value() default 15; //基本数据类型
}
// 使用注解
// 数组赋值时,值使用{}包裹,如果数组中只有一个值,可以省略{}
@MyAnno(per = Person.P1, anno2 = @MyAnno2, strs={"bbb", "ccc"})
public class Worker { // 自定义类
//成员变量、属性
}
注意:
-
如果注解中只有一个属性且名为value,不论value的类型是什么,则对其赋值时value可省略,直接定义值即可,如
@SuppressWarnings(“all”)
-
对同一个类或者方法等可以同时使用多个不同的注解
4. 元注解
用于描述注解的注解,在自定义注解的上一行写元注解,有以下四种:
(1) @Target
:描述注解能作用的位置
属性:ElementType[] value(); 其中ElementType是枚举类型,常用取值:
- TYPE 表示可以作用于类上
- METHOD 表示可以作用于方法上
- FIELD 表示可以作用于变量上
(2) @Retention
:描述注解被保留的阶段
属性:RetentionPolicy value(); 其中RetentionPolicy是枚举类型,取值:
- RUNTIME 表示当前注解会被保留到class文件中,并被JVM读取到,此值最为常用, 还可取值SOURCE,CLASS
(3) @Documented
:描述注解可被抽取到API文档中
(4) @Inherited
:描述注解可被继承:如果父类使用了被此元注解描述的注解,则继承此类的子 类即使没有写任何注解,也自动被此注解描述
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//自定义注解Pro
public @interface Pro {
String className();
String methodName();
}
5. 获取注解的属性值
// 使用上述自定义注解Pro
@Pro(className = "cn.itcast.annotation.Demo1", methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception {
// 1. 使用该类的字节码文件对象解析注解
Class<ReflectTest> reflectTestClass = ReflectTest.class;
// 2. 获取指定的注解对象
Pro an = reflectTestClass.getAnnotation(Pro.class);
// 第二步其实就是在内存中生成了一个该注解接口的子类实现对象
/*
public class ProImpl implements Pro{
public String className(){
return "cn.itcast.annotation.Demo1";
}
public String methodName(){
return "show";
}
}
*/
// 3. 调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
System.out.println(className); //cn.itcast.annotation.Demo1
System.out.println(methodName); //show
}
}
注意:使用多个注解时,调用Class对象的空参getAnnotation()方法可以获取所有注解对象,返回 Annoation[]