Java 反射
Java 能够反射的前提:已经加载过这个类,就可以通过类名来寻找到这个类的所有相关信息
Java Reflection
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的成员变量和方法
生成动态代理
Java反射机制研究及应用
反射相关的主要API:java.lang.Class
:代表一个类java.lang.reflect.Method
:代表类的方法java.lang.reflect.Field
:代表类的成员变量java.lang.reflect.Constructor
:代表类的构造方法
Class 类
反射可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
Class本身也是一个类
Class 对象只能由系统建立对象
一个类在 JVM 中只会有一个Class实例
一个Class对象对应的是一个加载到 JVM 中的一个 .class 文件
每个类的实例都会记得自己是由哪个 Class 实例所生成
通过 Class 可以完整地得到一个类中的完整结构
实例化 Class 类对象(四种方法)
前提:若已知具体的类,通过类的
class
属性获取,该方法 最为安全可靠,程序性能最高
实例:Class clazz = String.class;
前提:已知某个类的实例,调用该实例的
getClass()
方法获取 Class 对象
实例:Class clazz = “www.xyd.com”.getClass();
前提:已知一个类的全类名,且该类在类路径下,可通过 Class 类的静态方法
forName()
获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName (“java.lang.String”);
其他方式(不做要求)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
通过反射调用类的完整结构
使用反射可以取得:
1. 实现的全部接口
public Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
2. 所继承的父类
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
3. 全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有 public 构造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。
Constructor类中:
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
4. 全部的方法
public Method[] getDeclaredMethods()
返回此 Class 对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此 Class 对象所表示的类或接口的 public 的方法
Method类中:
public Class<?> getReturnType()
取得全部的返回值
public Class<?>[] getParameterTypes()
取得全部的参数
public int getModifiers()
取得修饰符
5. 全部的Field
public Field[] getFields()
返回此Class对象所表示的类或接口的 public 的 Field。
public Field[] getDeclaredFields()
返回此Class对象所表示的类或接口的全部Field。
Field方法中:
public int getModifiers()
以整数形式返回此 Field 的修饰符
public Class<?> getType()
得到Field的属性类型
public String getName()
返回Field的名称。
6. 类所在的包
Package getPackage()
通过反射调用类中的指定方法、指定属性
1. 调用指定方法
通过反射,调用类中的方法,通过Method类完成。
步骤:
通过 Class 类的
getMethod (String name, Class…parameterTypes)
方法取得一个 Method 对象,并设置此方法操作时所需要的参数类型。之后使用
Object invoke(Object obj, Object[] args)
进行调用,并向方法中传递要设置的 obj 对象的参数信息。
Object invoke(Object obj, Object … args)
说明:
Object 对应原方法的返回值,若原方法无返回值,此时返回 null
若原方法若为静态方法,此时形参 Object obj 可为 null
若原方法形参列表为空,则 Object[] args 为 null
若原方法声明为 private,则需要在调用此 invoke() 方法前,显式调用方法对象的setAccessible(true) 方法,将可访问 private 的方法。
2. 调用指定属性
在反射机制中,可以直接通过 Field 类操作类中的属性,通过 Field 类提供的 set() 和 get() 方法就可以完成设置和取得属性内容的操作。
public Field getField(String name)
返回此 Class 对象表示的类或接口的指定的public 的 Field。
public Field getDeclaredField(String name)
返回此 Class 对象表示的类或接口的指定的Field。
在Field中:
public Object get(Object obj)
取得指定对象 obj 上此 Field 的属性内容
public void set(Object obj,Object value)
设置指定对象 obj 上此 Field 的属性内容
注:在类中属性都设置为 private 的前提下,在使用 set() 和 get() 方法时,首先要使用 Field 类中的 setAccessible(true)
方法将需要操作的属性设置为可以被外部访问。
public void setAccessible(true)
访问私有属性时,让这个属性可见。
Java 动态代理
Proxy :专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。
创建一个动态代理类所对应的Class对象
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
直接创建一个动态代理对象
注意
如果一个对象想要通过 Proxy.newProxyInstance
方法被代理,那么这个对象的类一定要有相应的接口。
动态代理步骤
创建一个实现接口 InvocationHandler 的类,它必须实现
invoke
方法,以完成代理的具体操作。创建被代理的类以及接口
通过 Proxy 的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
创建一个Subject接口代理通过 Subject 代理调用 RealSubject 实现类的方法
- 本文作者: Kelly Liu
- 本文链接: http://tiantianliu2018.github.io/2019/10/24/Java-反射/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!