Java Anotation || Java Reflection 使用方法
Java Annotation
Annotation是从JDK5.0开始引入的新技术
Annotation的作用:
不是程序本身,可以对程序做出解释 **可以被其他程序(如编译器等)读取**
Annotation的使用:
附加在包,类,方法,属性等上,添加额外的辅助信息 我们可以通过反射机制编程实现对这些元数据的访问
内置注解
- @Override
- @Deprecated
- @SuppressWarning
eg 方法重写注解
1 | // target 作用在METHOD上 |
元注解
元注解的作用是负责解释其他注解
Java定义了四个标注的mete-annotation类型,他们被用来提供对其他annotation类型作说明,这些类型和他们支持的类可以在Java.lang.annotation包中找到。
@Target:用于描述注解的使用范围
支持的类型有
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}@Retention:表示需要在什么级别保存该注解信息
SOURCE < CLASS < RUNTIME
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}@Document:说明该注解将被包含在JavaDoc中
@Inherited:说明子类可以继承父类中的该注解
自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
注意
- 使用@interface来声明注解
- 每一个方法实际上都是声明了一个配置参数
- 方法名称就是参数的名称 —》 参数类型 参数名 ()
- 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,Enum)
- 可以通过default来声明参数的默认值,一般使用空字符串,0作为默认值
- 如果只有一个参数成员,一般参数名为value,在使用注解时可以省略注解属性名字
- 使用注解元素必须要有值,可以通过default值省略传值
例子
1 | /** |
注解信息获取
通过反射获取注解信息!
Java Reflection
通过反射使Java动态化。
反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,可以直接操作任意对象的内部属性及方法
Class对象
加载完类之后,在堆内存的方法区中会产生一个Class类型的对象(一个类只有一个Class对象),该对象包含了完整的类的结构信息。
正常: 引入包类名称 –> 通过new实例化 –> 取得实例化对象
反射: 实例化对象 –> getClass() –> 得到完整的包类名称
反射特点
优点:动态创建对象和编译,更为灵活
缺点:是一种解释操作,影响性能。
基本实例
1 | package org.example.learning; |
Class对象方法
Field,Method,Constructor,SuperClass,Interface,Annotation……
- 实现的全部接口Interface
- 所继承的父类SuperClass
- 全部的方法Method
- 全部的Field
- 注解Annotation
- …….
等等等…. 可见有很多方法了,例如
newInstance() 生成对象
getAnnotation() 获取注解信息
补充
- 所有类型都有Class对象?..
int.class表示基本数据类型int的Class对象
TYPE是Integer中的静态常量,表示的是基本数据类型int的class实例
Integer.class表示引用数据类型Integer的class对象
注意:由.class来创建Class对象的引用时,不会自动初始化Class对象.
1 | public static void main(String[] args) { |
类加载内存分析
Java内存
- 堆
- 存放new的对象以及数组
- 可以被所有的线程共享,不会存放别的对象引用
- 栈
- 存放基本变量类型(会包含基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里的具体地址)
- 方法区
- 可以被所有的线程共享
- 包含了所有的class和static变量
加载过程
- 加载(加载class字节码内容至内存中,在方法区保存)
- 链接(合并至JVM允许状态之中,从方法区中将数据加载为对于Class对象,保存在堆中)
- 验证(确保类规范)
- 准备(在方法区中为所有类变量分配内存并设置默认初始值)
- 解析(将虚拟机常量池内符号引用(变量名)替换为直接引用(地址)的过程)
- 初始化(Class对象创建初始化)(主动引用/被动引用——只有主动引用才会发生类的初始化)
- 主动引用(发生类的初始化)
- 虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员
- 反射调用
- 初始化类时,优先初始化父类
- 被动引用(不会发生类的初始化)
- 访问一个静态域,只有真正声明这个域的类才会初始化(子类调用父类静态变量,不会导致子类初始化)
- 数组定义类引用,不会触发类的初始化
- 引用final常量不会触发类的初始化(在链接阶段就存入了调用类的常量池中)
- 主动引用(发生类的初始化)
类加载器
类加载:将class文件加载至内存,并生成一个代表类的Class对象作为方法区中类数据的访问入口
类缓存:类被加载后,将缓存一段时间,JVM垃圾回收机制可以回收Class对象
分类
- 引导类加载器:负责Java平台核心库
- 扩展类加载器:负责jre/lib/ext目录下jar包
- 系统类加载器:负责加载项目下的类与jar包
- 自定义加载器
1 | public static void main(String[] args) { |
Class对象方法
获取类的运行时结构
剩余不做更多演示
获得名字
获得属性
获得方法
获得构造器
获得注解
1 | public static void main(String[] args) throws NoSuchFieldException { |
动态创建对象执行方法
调用方法
见代码
操作属性
见代码
1 | public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { |
补充
invoke(Object, Object..args) 调用方法 目标对象, 参数
set(Object, Object… args) 修改属性 目标对象,参数
setAccessible(boolean)
Method,Field,Constructor对象都有此方法
启动或禁用访问安全检查的开关
允许访问可以提高反射效率,但也使得私有成员也可以访问
default false,反射对象应实施Java语言访问检查
性能分析
- 普通方式调用
- 反射方式调用
- 反射方式调用(关闭安全检测)
普通 >>>> 关闭安全检测反射方式 > 反射方式
反射操作泛型
在编译完成后,所有和泛型有关的类型全部擦除
Tpye:所有类型的公共父类接口
ParameterizedType:表示一种参数化类型,例如Collection
GenericArrayType:表示一种元素类型时参数化类型或者类型变量的数组类型
TypeVariable:是各种类型变量的公共父类接口
- 表示泛型类型参数或者又叫做类型变量。比如:void method(E e){}中的E就是该接口类型
WildcardType:代表一种通配符类型表达式
- 比如?, ? extends Number, ? super Integer | wildcard是一个单词:就是“通配符”
1 | void test1(List<String> stringList) {} |
获取注解信息
区别
- getAnnotations():返回此元素上存在的所有注解的数组,包括从父类继承的
- getDeclaredAnnotations():返回直接存在于此元素上的所有注解的数组,不包括父类的注解
使用
通过反射获取注解中的信息
1 | /** |