反射概述:
java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法
对于任意一个对象,都能够调用他的任意一个方法和属性
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
要想解剖一个类,必须先要获取该类的字节码对象
而解剖使用的就是class类中的方法,所以先要获取到每一个字节码文件所对应的class类型的对象
获取Class对象的三种方式
Object类中的get()方法,判断两个对象是否是同一个字节码文件
静态属性class,锁对象
Class类中静态方法forName(),读取配置文件
源文件阶段 | 字节码阶段 | 创建对象阶段 |
---|---|---|
Person.java | Person.java | Person p =new Person() |
Class clazz=class.forName(“类全名”) | Class clazz =Person.calss | Class clazz =p.getClass() |
读取配置文件 | 当作静态方法的锁对象 | 判断是否是同一个字节码对象 |
注意:任何对私有方法变量和构造方法都要暴力反射setAccessible(true)
获取全类名
String getName()通过反射获取成员变量
-
可见的:
Field getField(String)
-
所有的:
Field getDeclaredField("name")
-
获取值:
get(Object obj)
-
设置值:
set(Object obj,Object value)
-
注意: 设置获取值要传入对象
通过反射获取构造函数
-
公共的:
Constructor<T> getConstructor(类<?>... parameterTypes)
-
所有的:
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
-
有参构造方法创建对象:
T newInstance(Object... initargs)
-
空参构造方法创建对象:直接使用
Class中的newInstance
方法 -
注意:构造方法中有参数,则方法中要加
参数类型.class
,
通过反射获取成员方法
-
公共的:
Method getMethod(String name, 类<?>... parameterTypes)
-
所有的:
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
-
执行方法:
Object invoke(Object obj, Object... args)
-
注意:getMethod参数传入方法名和
参数列表.class
,执行方法传入对象
类加载器
类加载概述
当程序要使用某个类时,该类还未被加载到内存中,则系统会通过加载,连接,
初始化三步来实现对这个类进行初始化
-
加载
就是指将class文件读入内存,并为之创建一个class对象,任何列被使用时系统都会建立一个class对象 -
连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用 -
初始化
创建类的实例
访问类的静态方法,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.class
直接使用java.exe命令来运行某个主类
类加载器 | 加载器 | 作用 | 位置 |
---|---|---|---|
根类加载器 | Bootstrap ClassLoader | 也称为引导类加载器,负责java核心类的加载,比如System,string等, | 在jdk中的JRE的lib目录下rt.jar文件中 |
扩展类加载器 | Extension ClassLoader | 负责JRE的扩展目录中的jar包的加载 | 在JDK中JRE的lib目录下ext目录 |
系统类加载器 | System ClassLoader | 负责在jvm启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径 |
动态代理
实现动态代理包括三步:
(1). 新建委托类;
(2). 实现InvocationHandler接口,这是负责连接代理类和委托类的中间类必须实现的接口;
(3). 通过Proxy类新建代理类对象。
- 新建委托类
public interface Operate {
public void operateMethod1();
public void operateMethod2();
public void operateMethod3();
}
public class OperateImpl implements Operate {
@Override
public void operateMethod1() {
System.out.println("Invoke operateMethod1");
sleep(110);
}
@Override
public void operateMethod2() {
System.out.println("Invoke operateMethod2");
sleep(120);
}
@Override
public void operateMethod3() {
System.out.println("Invoke operateMethod3");
sleep(130);
}
private static void sleep(long millSeconds) {
try {
Thread.sleep(millSeconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Operate
是一个接口,定了了一些函数,我们要统计这些函数的执行时间。
OperateImpl
是委托类,实现Operate
接口。每个函数简单输出字符串,并等待一段时间。
动态代理要求委托类必须实现了某个接口,比如这里委托类OperateImpl
实现了Operate
,
- 实现 InvocationHandler 接口
public class TimingInvocationHandler implements InvocationHandler {
private Object target;
public TimingInvocationHandler() {}
public TimingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object obj = method.invoke(target, args);
System.out.println(method.getName() + " cost time is:" + (System.currentTimeMillis() - start));
return obj;
}
}
target
属性表示委托类对象。
InvocationHandler
是负责连接代理类和委托类的中间类必须实现的接口。其中只有一个
public Object invoke(Object proxy, Method method, Object[] args)
函数需要去实现,参数:
proxy
表示下面2.3 通过 Proxy.newProxyInstance()
生成的代理类对象。
method
表示代理对象被调用的函数。
args
表示代理对象被调用的函数的参数。
调用代理对象的每个函数实际最终都是调用了InvocationHandler
的invoke
函数。这里我们在invoke
实现中添加了开始结束计时,其中还调用了委托类对象target
的相应函数,这样便完成了统计执行时间的需求。
invoke
函数中我们也可以通过对method
做一些判断,从而对某些函数特殊处理。
- 通过 Proxy 类静态函数生成代理对象
public class Main {
public static void main(String[] args) {
// create proxy instance
TimingInvocationHandler timingInvocationHandler = new TimingInvocationHandler(new OperateImpl());
Operate operate = (Operate)(Proxy.newProxyInstance(Operate.class.getClassLoader(), new Class[] {Operate.class},
timingInvocationHandler));
// call method of proxy instance
operate.operateMethod1();
System.out.println();
operate.operateMethod2();
System.out.println();
operate.operateMethod3();
}
}
这里我们先将委托类对象new OperateImpl()
作为TimingInvocationHandler
构造函数入参创建timingInvocationHandler
对象;
然后通过Proxy.newProxyInstance(…)
函数新建了一个代理对象,实际代理类就是在这时候动态生成的。我们调用该代理对象的函数就会调用到timingInvocationHandler
的invoke
函数(是不是有点类似静态代理),而invoke
函数实现中调用委托类对象new OperateImpl()
相应的 method
(是不是有点类似静态代理)。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loader
表示类加载器
interfaces
表示委托类的接口,生成代理类时需要实现这些接口
h
是InvocationHandler
实现类对象,负责连接代理类和委托类的中间类
我们可以这样理解,如上的动态代理实现实际是双层的静态代理,开发者提供了委托类 B,程序动态生成了代理类 A。开发者还需要提供一个实现了InvocationHandler
的子类 C,子类 C 连接代理类 A 和委托类 B,它是代理类 A 的委托类,委托类 B 的代理类。用户直接调用代理类 A 的对象,A 将调用转发给委托类 C,委托类 C 再将调用转发给它的委托类 B。