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
 39- public 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
 21- public 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 | /** |