Java中的反射和代理

一、反射
1、概念

  能够分析类能力的程序称为反射。就是在运行状态中,对任意一个类,能知道这个类的所有方法和属性,对于任意一个对象来说,都能调用他的任意一个方法和属性。这就是Java语言的反射机制,主要就是增加程序的灵活性。

2、反射的使用

  (1)反射获取类信息的三种方式

// 方式一: 类名.class
Class c1 = Person.class;
// 方式二: Class.forName("全限定名(包路径+类名)")
Class c2 = Class.forName("com.exam.csdndemo.Person");
// 方式三: 对象.getClass()
Person person = new Person();
Class c3 = person.getClass();

  (2)反射获取类的名称、属性、构造方法、普通方法

// 方式一: 类名.class
Class c1 = Person.class;
// 获取类名
String className1 = c1.getName(); // 类名: com.exam.csdndemo.Person
String className2 = c1.getSimpleName(); // 类名: Person
// 获取属性
Field[] field1 = c1.getFields(); // 返回声明为public的属性
Field[] field2 = c1.getDeclaredFields(); // 返回所有的属性
Field field3 = c1.getDeclaredField("name"); // 返回name属性
// 获取构造方法
Constructor[] constructor1 = c1.getConstructors(); // 返回所有public构造器
Constructor[] constructor2 = c1.getDeclaredConstructors(); // 返回所有构造器
// 获取普通方法
Method[] method1 = c1.getMethods(); // 返回所有public方法
Method[] method2 = c1.getDeclaredMethods(); // 返回所有方法

  (3)反射通过类信息创建这个类的对象

// 方式一: 类名.class
Person person1 = Person.class.newInstance();
// 方式二: Class.forName("全限定名(包路径+类名)")
Person person2 = (Person) Class.forName("com.exam.csdndemo.Person").newInstance();
二、代理
1、概念

  为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。简单来说:代理可以在被代理类的基础上实现一些额外的功能,对被代理类做一个增强。
  代理模式又分为静态代理和动态代理。静态代理是在编译时就将接口、实现类、代理类全部手动完成,但如果我们需要很多的代理,每一个都这么手动的去创建实属浪费时间,而且会有大量的重复代码,此时我们就可以采用动态代理。动态代理可以在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能。

2、静态代理实现示例

  在代理类定义与目标类相同的方法,然后通过修改,执行代理类的方法来达到在原来的方法基础上进行扩充的目的。
  (1)创建一个DemoInterface接口

public interface DemoInterface {
    void method();
}

  (2)创建一个Demo类实现DemoInterface接口

public class Demo implements DemoInterface{
    @Override
    public void method() {
        System.out.println("正在执行method");
    }
}

  (3)创建一个DemoProxy类同样实现DemoInterface接口

public class DemoProxy implements DemoInterface{
    // 创建Demo对象
    private Demo demo = new Demo();
    @Override
    public void method() {
        System.out.println("=======执行前======");
        demo.method(); // 调用原来的方法
        System.out.println("=======执行后======");
    }
}

  (4)创建一个DemoMain测试类来运行

public class DemoMain {
    public static void main(String[] args) {
        DemoInterface demoInterface = new DemoProxy();
        demoInterface.method();
    }
}

  (5)运行结果
在这里插入图片描述

  可以看到DemoProxy类的method方法对原来的Demo类的method方法做了一个增强,可以再method方法执行前后加上一些逻辑处理。

3、JDK动态代理实现示例

  JDK动态代理,利用反射机制生成一个代理类,在调用具体方法前调用InvokeHandler来处理,只能对实现了接口的类生成代理。

  (1)创建一个DemoInterface接口

public interface DemoInterface {
    void method();
}

  (2)创建一个Demo类实现DemoInterface接口

public class Demo implements DemoInterface{
    @Override
    public void method() {
        System.out.println("正在执行method");
    }
}

  (3)创建一个DemoProxy类实现InvocationHandler接口

public class DemoProxy implements InvocationHandler {
    // 要代理的真实对象
    private Object object;
    // 构造方法,给我们要代理的对象赋初值
    public DemoProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("=========执行前========");
        // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的invocationHandler对象的invoke方法来进行调用
        Object o = method.invoke(object,args);
        System.out.println("=========执行后========");
        return o;
    }
}

  每一个动态代理类都必须要实现InvocationHandler这个接口,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

  (4)创建一个DemoMain测试类来运行

public class DemoMain {
    public static void main(String[] args) {
        // 要代理的真实对象
        Demo demo = new Demo();
        // 传进去真实对象,最后通过真实对象来调用其方法
        InvocationHandler invocationHandler = new DemoProxy(demo);
        // 通过Proxy的newProxyInstance方法来创建我们的代理对象
        DemoInterface demoInterface = (DemoInterface) Proxy.newProxyInstance(demo.getClass().getClassLoader(),demo.getClass().getInterfaces(),invocationHandler);
        // 执行方法
        demoInterface.method();
    }
}

  为什么我们这里可以将其转化为DemoInterface类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是DemoInterface类型,所以就可以将其转化为DemoInterface类型了。

  (5)运行结果
在这里插入图片描述

3、CGLib动态代理实现示例

  CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类。CGLib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)。需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
  (1)创建一个Demo类

public class Demo {
    public void method(){
        System.out.println("正在执行method");
    }
}

  (2)创建一个DemoProxy类实现MethodInterceptor接口

public class DemoProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("==========执行前=========");
        Object obj = methodProxy.invokeSuper(o,objects);// 调用被代理类的方法
        System.out.println("==========执行后=========");
        return obj;
    }
}

  (3)创建一个DemoMain测试类来运行

public class DemoMain {
    public static void main(String[] args) {
        // 利用Enhancer创建代理类
        Enhancer enhancer = new Enhancer();
        // 继承被代理类
        enhancer.setSuperclass(Demo.class);
        // 设置回调
        enhancer.setCallback(new DemoProxy());
        // 生成代理对象
        Demo demo = (Demo) enhancer.create();
        // 在调用方法时会被我们设置的方法拦截器所拦截
        demo.method();
    }
}

  (4)运行结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值