反射
JAVA反射机制是在运行状态中,获取任意一个类的结构 , 创建对象 , 得到方法,执行方法 , 属性。
这种在运行状态动态获取信息以及动态调用对象方法的功能被称为java语言的反射机制。
使用场景
当我们知道要使用的类是什么的时候可以直接new出来,但是不知道的时候呢?这时候就要用到反射了。
反射,即在运行时才知道要使用的类是什么,并且要获取到类的结构、属性,调用类的方法。
例如:
类加载器:运行时需要使用某个类就加载某个类
此处简单介绍一下类加载器
类加载器
Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分, 负责动态加载Java类到Java虚拟机的内存空间中。
java默认有三种类加载器,BootstrapClassLoader、ExtensionClassLoader、App ClassLoader。
- BootstrapClassLoader(引导启动类加载器):
- 嵌在JVM内核中的加载器,该加载器是用C++语言写的,主要负载加载JAVA_HOME/lib下的类库,引 导启动类加载器无法被应用程序直接使用。
- ExtensionClassLoader(扩展类加载器):
- ExtensionClassLoader是用JAVA编写,且它的父类加载器是Bootstrap。 是由sun.misc.Launcher$ExtClassLoader实现的,主要加载JAVA_HOME/lib/ext目录中的类 库。 它的父加载器是BootstrapClassLoader
- App ClassLoader(应用类加载器):
- App ClassLoader是应用程序类加载器,负责加载应用程序classpath目录下的所有jar和class文 件。它的父加载器为Ext ClassLoader
双亲委派模型:类加载的方式
如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类) 时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。
使用
使用反射获取对象的步骤:
1、获取类的 Class 对象实例
要想了解一个类,必须先要获取到该类的字节码文件对象.
在Java中,每一个字节码文件,被加载到内存后,都存在一个对应的Class类型的对象。(一个class文件 在内存中不会存在两个类对象 )
获取Class对象:
-
- 如果在编写代码时, 知道类的名称, 且类已经存在, 可以通过 包名.类名.class 得到一个类的类对象
- 如果拥有类的对象, 可以通过 Class 对象.getClass() 得到一个类的类对象
- 如果在编写代码时, 知道类的名称 , 可以通过 Class.forName(包名+类名): 得到一个类的 类对象
上述的三种方式, 在调用时, 如果类在内存中不存在, 则会加载到内存 ! 如果类已经在内存中存在, 不会重复加载, 而是重复利用 !
特殊的类对象
基本数据类型的类对象:
-
- 基本数据类型.clss
- 包装类.type
基本数据类型包装类对象:
-
- 包装类.class
2、根据 Class 对象实例获取 Constructor 对象
通过指定的参数类型, 获取指定的单个构造方法:getConstructor(参数类型的class对象数组)
: 构造方法: Book(String name,int price)
得到这个构造方法的代码: Constructor c = b.getClass().getConstructor(String.class,int.class);
获取构造方法数: getConstructors();
获取所有权限的单个构造方法: getDeclaredConstructor(参数类型的class对象数组)
获取所有权限的构造方法数组: getDeclaredConstructors();
3、使用 Constructor 对象的 newInstance 方法获取反射类对象
newInstance(Object... para) // 参数: 是一个Object类型可变参数, 传递的参数顺序 必须匹配构造方法中形式参数列表的顺序
setAccessible(boolean flag) // 如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的方法)
4、通过Class对象获取类的一个Method,并执行
//根据参数列表的类型和方法名, 得到一个方法(public修饰的) getMethod(String methodName , class.. clss) // 得到一个类的所有方法 (public修饰的) getMethods(); // 根据参数列表的类型和方法名, 得到一个方法(除继承以外所有的:包含私有, 共有, 保护, 默认) getDeclaredMethod(String methodName , class.. clss) //得到一个类的所有方法 (除继承以外所有的:包含私有, 共有, 保护, 默认) getDeclaredMethods(); // 执行: //参数1. 要调用方法的对象 参数2. 要传递的参数列表 invoke(Object o,Object... para) // 获取方法的方法名称 getName() // 如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的方法) setAccessible(boolean flag)
5、通过Class对象获取类的属性(Field)
// 根据属性的名称, 获取一个属性对象 (所有属性) getDeclaredField(String filedName) // 获取所有属性 getDeclaredFields() // 根据属性的名称, 获取一个属性对象 (public属性) getField(String filedName) //获取所有属性 (public) getFields() // Field 方法 // 参数: 要获取属性的对象 // 获取指定对象的此属性值 get(Object o ); // 参数1. 要设置属性值的 对象 // 参数2. 要设置的值 // 设置指定对象的属性的值 set(Object o , Object value); // 获取属性的名称 getName() // 如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的属性) setAccessible(boolean flag)
6、获取注解信息
// 获取类/属性/方法的全部注解对象 Annotation[] annotations1 = Class/Field/Method.getAnnotations(); for (Annotation annotation : annotations1) { System.out.println(annotation); } // 根据类型获取类/属性/方法的注解对象 注解类型 对象名 = (注解类型) c.getAnnotation(注解类型.class);
内省(Introspector)
基于反射 , java所提供的(java.beans包下)一套应用到JavaBean的API,其中封装了对反射的操作。
bean类:
- 一个定义在包中的类
- 拥有无参构造器
- 所有属性私有,
- 所有属性提供get/set方法
- 实现了序列化接口
方法
| 变量和类型 | 方法 | 描述 |
|---|---|---|
static String |
decapitalize(String name) |
获取字符串并将其转换为普通Java变量名称大小写的实用方法。
|
static void |
flushCaches() |
刷新所有Introspector的内部缓存。
|
static void |
flushFromCaches(类<?> clz) |
刷新Introspector的给定类的内部缓存信息。
|
static BeanInfo |
getBeanInfo(类<?> beanClass) |
对Java Bean进行内省并了解其所有属性,公开方法和事件。
|
static BeanInfo |
getBeanInfo(类<?> beanClass, int flags) |
对Java bean进行内省并了解其所有属性,公开方法和事件,并遵守一些控制标志。
|
static BeanInfo |
getBeanInfo(类<?> beanClass, 类<?> stopClass) |
对Java bean进行内省,并在给定的“停止”点下了解其属性,公开方法。
|
static BeanInfo |
getBeanInfo(类<?> beanClass, 类<?> stopClass, int flags) |
对Java Bean进行内省并了解其所有属性,公开方法和事件,低于给定的
stopClass点,受某些控制 flags 。 |
static String[] |
getBeanInfoSearchPath() |
获取将用于查找BeanInfo类的包名称列表。
|
static void |
setBeanInfoSearchPath(String[] path) |
更改将用于查找BeanInfo类的包名称列表。
|
使用内省获取Bean的封装对象BeanInfo
BeanInfo方法:
| 变量和类型 | 方法 | 描述 |
|---|---|---|
BeanInfo[] |
getAdditionalBeanInfo() |
此方法使当前
BeanInfo对象能够返回其他 BeanInfo对象的任意集合, BeanInfo对象提供有关当前Bean的其他信息。 |
BeanDescriptor |
getBeanDescriptor() |
返回提供有关bean的整体信息的bean描述符,例如其显示名称或其自定义程序。
|
int |
getDefaultEventIndex() |
当使用此bean时,bean可能具有通常应用的默认事件。
|
int |
getDefaultPropertyIndex() |
当自定义此bean时,bean可能具有通常更新的默认属性。
|
EventSetDescriptor[] |
getEventSetDescriptors() |
返回bean的事件描述符,用于定义此bean触发的事件类型。
|
Image |
getIcon(int iconKind) |
返回可用于表示工具箱或工具栏中的bean的图像。
|
MethodDescriptor[] |
getMethodDescriptors() |
返回bean的方法描述符,用于定义此bean支持的外部可见方法。
|
PropertyDescriptor[] |
getPropertyDescriptors() |
返回bean的所有属性的描述符。
|
getPropertyDescriptors(): 获取bean类的 get/set方法 数组
Method getReadMethod(); 获取一个get方法
Method getWriteMethod(); 获取一个set方法
有可能返回null 注意 ,加判断
| 变量和类型 | 方法 | 描述 |
|---|---|---|
PropertyEditor |
createPropertyEditor(Object bean) |
使用当前属性编辑器类构造属性编辑器的实例。
|
boolean |
equals(Object obj) |
将此
PropertyDescriptor与指定的对象进行比较。 |
类<?> |
getPropertyEditorClass() |
获取已为此属性注册的任何显式PropertyEditor类。
|
类<?> |
getPropertyType() |
返回属性的Java类型信息。
|
方法 |
getReadMethod() |
获取应该用于读取属性值的方法。
|
方法 |
getWriteMethod() |
获取应该用于写入属性值的方法。
|
int |
hashCode() |
返回对象的哈希码值。
|
boolean |
isBound() |
对“绑定”属性的更新将导致在更改属性时触发“PropertyChange”事件。
|
boolean |
isConstrained() |
尝试更新“Constrained”属性将导致在更改属性时触发“VetoableChange”事件。
|
void |
setBound(boolean bound) |
对“绑定”属性的更新将导致在更改属性时触发“PropertyChange”事件。
|
void |
setConstrained(boolean constrained) |
尝试更新“Constrained”属性将导致在更改属性时触发“VetoableChange”事件。
|
void |
setPropertyEditorClass(类<?> propertyEditorClass) |
通常使用PropertyEditorManager找到PropertyEditors。
|
void |
setReadMethod(方法 readMethod) |
设置应该用于读取属性值的方法。
|
void |
setWriteMethod(方法 writeMethod) |
设置应该用于写入属性值的方法。
|
posted on
浙公网安备 33010602011771号