目录
什么是注解?
它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能,注解相关类都包含在java.lang.annotation包中。
注解给谁用?给编译器、给解析程序用。
ps: 注解区别于注释,注释是文字描述的,给程序员看的。
注解的作用?
- 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
注解的类型
元注解
用于定义注解的注解,包括@Retention
(标明注解被保留的阶段)、@Target(标明注解使用的范围)、@Inherited(标明注解可继承)、@Documented(标明是否生成javadoc文档)
@Retention:定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target:指定被修饰的Annotation可以放置的位置(被修饰的目标)
@Target(ElementType.TYPE) //接口、类
@Target(ElementType.FIELD) //属性
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE) //局部变量
@Target(ElementType.ANNOTATION_TYPE) //注解
@Target(ElementType.PACKAGE) //包
注:可以指定多个位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用
@Inherited:指定被修饰的Annotation将具有继承性
@Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档
Java自带/预定义的注解
@Override:检测被该注解标注的方法是否是继承自父类(接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告
自定义注解
可以根据自己的需求定义注解。
什么是自定义注解?
- 格式
元注解
public @interface 注解名称{
属性列表;
}
注解本质上就是一个接口,该接口默认继承Annotation接口
- 举例
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//@Documented – 注解是否将包含在JavaDoc中
//@Retention – 什么时候使用该注解
//@Target – 注解用于什么地方
//@Inherited – 是否允许子类继承该注解
1。 定义注解
@Target(ElementType.METHOD)//作用目标是方法
@Retention(RetentionPolicy.RUNTIME)//保留策略使用RUNTIME:注解会在class字节码文件中存在,在运行时可以通过反射获取到
public @interface MyAnnotationTest {
String name() default "hello";
}
2. 注解处理器
public class ReflectProcessor {
public void parseMethod(final Class<?> clazz) throws Exception {
final Object obj = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {});
final Method[] methods = clazz.getDeclaredMethods();
for (final Method method : methods) {
final MyAnnotationTest myAnnotationTest = method.getAnnotation(MyAnnotationTest.class);
if (null != my) {
System.out.println("方法名:");
System.out.println(method.getName());
method.invoke(obj, my.name());
}
}
}
}
3. 测试一下注解
public class ReflectTest {
@MyAnnotationTest
public static void sayHello1(final String name) {
System.out.println("Hi, " + name);
}
/** 输出结果
方法名:
sayHello1
Hi, hello
*/
@MyAnnotationTest(name = "kuaile")
public static void sayHello2(final String name) {
System.out.println("Hi, " + name);
}
/** 输出结果
方法名:
sayHello2
Hi, kuaile
*/
public static void main(final String[] args) throws Exception {
final ReflectProcessor reflectProcessor = new ReflectProcessor();
reflectProcessor.parseMethod(ReflectTest.class);
}
}
@Retention – 定义该注解的生命周期
● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后 就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括
● ElementType.CONSTRUCTOR: 用于描述构造器
● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
● ElementType.LOCAL_VARIABLE: 用于描述局部变量
● ElementType.METHOD: 用于描述方法
● ElementType.PACKAGE: 用于描述包
● ElementType.PARAMETER: 用于描述参数
● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明