Java反射
反射就是Reflection,Java反射是指程序在运行期可以拿到一个对象的所有信息。反射是为了解决在运行期,对某个实例一无所知的情况下,如何调用期方法。
Class类
class
是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class
,将其加载进内存中,每加载一种class
, JVM就为其创建一个Class
类型的实例,并关联起来。
- Class类
1 | public final class Class{ |
- 以`String`类为例,当JVM加载`String`时,首先读取String。class文件到内存,然后JVM为String类创建一个Class实例并关联起来:
Class cls = new Class(String);
- 这个Class实例是由JVM并且只能有JVM创建。
一个Class实例包含了该class的所有完整信息:包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。
这种通过Class实例获取class信息的方法称为反射(Reflection)。
如何获取一个class的Class实例:
- 1.直接通过一个class的静态变量获取
Class cls = String.class;
- 2.通过实例变量提供的getClass()方法获取
Class.cls = s.getClass();
- 3.如果知道一个class名字,可以通过静态方法
Class.forName()
获取:Class cls = Class.forName("java.lang.String");
- 1.直接通过一个class的静态变量获取
Class实例比较
- 由于JVM创建的Class实例是唯一的,通过上述三个方法获取的实例均是相同的
创建Class对应类型的实例:
- newInstance相当于new String()
- 只能调用public的无参数构造方法
1 | Class cls = String.class; |
- 动态加载
- JVM在执行Java程序的时候,并不是一次性把所有用到的class加载到内存,而是第一次用到class时才加载。
- 动态加载class的特性对于Java程序非常重要。利用JVM动态加载class的特性,我们才能在运行期根据条件加载不同的实现类。
访问字段
Class类提供了几个方法来获取字段:
getFiled(name)
获取包括父类的public类中的filedgetDeclaredFiled(name)
获取当前类的filedgetFileds()
获取所有public的filedgetDeclaredFileds()
获取当前类的所有filed
Filed字段包含
getName()
字段名臣,getType()
字段类型,getModifiers()
修饰符获取字段实例后,想要获取指定字段值
Filed.get(Object)
如Object value = f.get("name");
- 如果该字段被修饰为private,可修改作用域
f.setAccessible(true);
设置字段值
Filed.set(Object name, Object value)
- 如果不可访问,需修改作用域
调用方法
Class几种方法获取Method
getMethod(name, Class...)
获取某个public的Method(包含父类)getDecleardMethod(name, Class...)
获取当前类的MethodgetMethods()
获取所有public的method(包括父类)getDecleardMethods()
获取当前类所有的Method
一个Method对象包含一个方法的所有信息
getName()
getReturnType()
方法返回值类型getParameterTypes()
返回方法的参数类型,数组{String.class, int.class}getModifiers()
方法的修饰符,是一个int
调用方法
m.invoke(Class clazz, para)
调用静态方法:
m.invoke(null, para)
调用非public方法,需设定
Method.setAccessible(true)
修改作用域- JVM如果存在SecurityManager,有可能会阻止
- 如java和javax开头的包类调用,会被阻止确保核心库安全
多态:遵循多态特性
调用构造方法
通过newInstance只能实例public的无参构造方法,而其他的不可以。
为了调用任意的构造方法,Java的反射API提供了Constructor对象,它包含一个构造方法的所有信息,可以创建一个实例。调用方法如下
getConstructor(Class...)
:获取某个public的Constructor;getDeclaredConstructor(Class...)
:获取某个Constructor;getConstructors()
:获取所有public的Constructor;getDeclaredConstructors()
:获取所有Constructor。
返回依然是一个实例。
- 调用的总是当前的构造方法,和父类无关
- 调用非public的构造方法,需要setAccessible(true)修改作用域
获取继承关系
可通过getSupperclass()
获取父类
可通过getInterfaces()
获取Interface
通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。
动态代理
Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以再运行期间动态创建某个interface的实例,
1 | import java.lang.reflect.InvocationHandler; |