Java-反射

反射概述:

java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法
 对于任意一个对象,都能够调用他的任意一个方法和属性
 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
要想解剖一个类,必须先要获取该类的字节码对象
而解剖使用的就是class类中的方法,所以先要获取到每一个字节码文件所对应的class类型的对象

获取Class对象的三种方式

Object类中的get()方法,判断两个对象是否是同一个字节码文件
静态属性class,锁对象
Class类中静态方法forName(),读取配置文件

源文件阶段字节码阶段创建对象阶段
Person.javaPerson.javaPerson p =new Person()
Class clazz=class.forName(“类全名”)Class clazz =Person.calssClass 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,执行方法传入对象

类加载器

类加载概述
当程序要使用某个类时,该类还未被加载到内存中,则系统会通过加载,连接,
初始化三步来实现对这个类进行初始化

  1. 加载
    就是指将class文件读入内存,并为之创建一个class对象,任何列被使用时系统都会建立一个class对象

  2. 连接
    验证 是否有正确的内部结构,并和其他类协调一致
    准备 负责为类的静态成员分配内存,并设置默认初始化值
    解析 将类的二进制数据中的符号引用替换为直接引用

  3. 初始化
    创建类的实例
    访问类的静态方法,或者为静态变量赋值
    调用类的静态方法
    使用反射方式来强制创建某个类或接口对应的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类新建代理类对象。

  1. 新建委托类
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

  1. 实现 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表示代理对象被调用的函数的参数。

调用代理对象的每个函数实际最终都是调用了InvocationHandlerinvoke函数。这里我们在invoke实现中添加了开始结束计时,其中还调用了委托类对象target的相应函数,这样便完成了统计执行时间的需求。
invoke函数中我们也可以通过对method做一些判断,从而对某些函数特殊处理。

  1. 通过 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(…)函数新建了一个代理对象,实际代理类就是在这时候动态生成的。我们调用该代理对象的函数就会调用到timingInvocationHandlerinvoke函数(是不是有点类似静态代理),而invoke函数实现中调用委托类对象new OperateImpl()相应的 method(是不是有点类似静态代理)。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

loader表示类加载器
interfaces表示委托类的接口,生成代理类时需要实现这些接口
hInvocationHandler实现类对象,负责连接代理类和委托类的中间类

我们可以这样理解,如上的动态代理实现实际是双层的静态代理,开发者提供了委托类 B,程序动态生成了代理类 A。开发者还需要提供一个实现了InvocationHandler的子类 C,子类 C 连接代理类 A 和委托类 B,它是代理类 A 的委托类,委托类 B 的代理类。用户直接调用代理类 A 的对象,A 将调用转发给委托类 C,委托类 C 再将调用转发给它的委托类 B。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值