- 注解
- 概述: 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
- 注解的作用:
- 编写文档:通过代码里标识的注解生成文档【例如,生成文档javadoc文档】
@author @version @param @return
- 代码分析:通过代码里标识的注解对代码进行分析【例如,注解的反射】
注解的底层实现原理 : 就是通过反射机制完成的
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【例如,Override,FunctionalInterface】
- 常见注解:
- @author:用来标识作者名
- @version:用于标识对象的版本号,适用范围:文件、类、方法。
- @Override:
用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。
注解和注释是完全不同的
- 注解会影响代码的运行, 注释不会影响代码的运行;
- 注释是给程序员看的, 注解不是给人看的, 是对于程序的编译和运行起到一定作用的
- 自定义注解
- 定义格式:
元注解
public @interface 注解名称{
属性列表;
}
- 注解本质上就是一个接口,该接口默认继承Annotation接口
相当于:
public interface MyAnnotation extends java.lang.annotation.Annotation {}
举例 :
public @interface Person{}
- 注解不需要写任何的逻辑, 因为注解式标注
- 元注解
- 元注解:用来描述注解的注解
- 分类:
@Target:描述注解能够作用的位置(指定使用的地方)
value值:是一个ElementType[]
常用取值:
1、ElementType.TYPE : 针对类和接口使用
2、ElementType.METHOD : 针对方法使用
3、ElementType.FILED : 针对变量使用
@Retention:注解被保留的阶段
value值:是一个RetentionPolicy枚举RetentionPolicy(翻译: 保留策略)
取值:
- RetentionPolicy.SOURCE---【在源代码中不会到字节码文件中】
编译器运行时, 进行识别(编译时期识别), 例如@Override
2、RetentionPolicy.CLASS---【编译到字节码文件中但是运行时jvm不会读取】注解信息保留到类对应的class文件中
3、RetentionPolicy.RUNTIME--【编译到字节码文件中运行时jvm会读取,运行时使用】运行时期生效的注解一般都是筛选的作用 例如: @FunctionalInterface
例如: 程序运行时起作用的,@WebServlet, 代码运行时,检测哪些类型是Servlet
@Documented :描述注解是否被抽取到API文档中
@Inherited:注解是否被子类继承
代码
package com.ujiuye.ano; |
- 注解通过反射机制解析运行
代码
package com.ujiuye.ano; |
package com.ujiuye.ano;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
// 测试带有自定义的InitMethod注解的方法,通过反射机制运行
public class TestInitMethod {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
// 1. 获取到带有注解的类型在内存中对应的Class字节码文件对象
Class c = UseInitMethod.class;
// 2. 通过Class类型对象, 获取到所有方法
Method[] m = c.getDeclaredMethods();
// 3. 遍历m数组,获取到每一个方法
for(Method me : m){
// 注意 : Method类型的父类Accessiable中继承给Method的方法
// isAnnotationPresent(Class 注解): 验证方法上是否带有参数的注解
// 如果带有返回true, 如果没有返回false
boolean boo = me.isAnnotationPresent(InitMethod.class);
if(boo){// 方法上带有InitMethod注解,马上运行
me.invoke(c.newInstance());
}
}
}
} |
@Override注解模拟解析
package com.ujiuye.ano;
public class Zi extends FU{
/*
剖析Override注解解析方式:
1) 当类进入到编译阶段,马上检测当前类型中,有哪些方法使用了Override注解
2) 将所有的带有Override方法获取到
3) 遍历获取每一个方法,到父类类型中,寻找,是否有与重写的方法一样的方法声明(包括修饰符的检查)
a : 父类有, Override成立,不报错
b : 父类没有, 或者权限不对,报错
*/
@Override
public void show(){
System.out.println("我是子类重写");
}
/*@Override
public void fun(){
System.out.println("我是子类重写");
}*/
} |
- 注解的属性
- 属性的作用: 可以让用户在使用注解时传递参数,让注解的功能更加强大。
- 属性的格式:
public @interface 注解名称{
属性列表;
}
- 格式1:数据类型 属性名();
- 格式2:数据类型 属性名() default 默认值;
- 属性适用的数据类型
- 八种基本数据类型(int,float,boolean,byte,double,char,long,short)
- String类型,Class类型,枚举类型,注解类型
- 以上所有类型的一维数组
- 注意事项:
- 如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
2) 如果属性没有默认值,那么在使用注解时一定要给属性赋值。
代码
package com.ujiuye.ano; |
- 注解的解析
注解只是标注, 注解在加载时, 通过反射机制将注解需要完成的功能进行实现
在程序中使用(解析)注解的步骤(获取注解中定义的属性值):
1. 获取注解定义的位置的对象 (Class,Method,Field)
2. 获取指定的注解 Class类中方法: getAnnotation(Class)
3. 调用注解中的抽象方法获取配置的属性值
使用格式:
@注解名(属性名=属性值,属性名=属性值,属性名=属性值...)
代码
package com.ujiuye.ano; |