Java反射与代理模式

静态语言与动态语言

静态语言:是在编译是变量的数据类型即可以确定的语言。多数静态类型语言要求在使用变量之前必须声明数据类型。 即在编译时确定类型,绑定对象。
例如:C/C++、Java、C#
动态语言:运行时才确定数据类型的语言。程序运行时可该改变结构和数据类型。即运行时确定类型,绑定对象。
如:Rudy、Python 、JavaScript
动态语言相对静态语言来说最大的优点之一就是灵活,所以静态语言也在通过其他方法来趋近动态语言以去弥补静态语言的缺陷,如继承、接口(多态的实现就是最好的例子)

强类型与弱类型语言:

强类型语言:不同类型之间不能直接进行运算,必须要经过类型转换
Java、Python
弱类型语言:不同类型之间能直接进行运算
JavaScript

1.Java反射机制的概念

java的反射机制增强动态性

java反射机制:程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为 java 的反射机制(广泛用于各个框架中用于类之间的解耦,比如说Spring的IOC实现)。

Class类与java反射
反射机制很重要的一点就是“运行时”
注意:JVM并不是在一开始就把一个程序就所有的类都加载到内存中,而是到用的时候才把它加载进来。
当Java虚拟机载入一个类的时候,它就会自动创建一个Class类的实例来表示这个类,该实例中包含了完整的类的结构信息。

利用Class实例实现反射机制
需要注意的是Class类的构造函数是private的,即不能通过new的方式来创建Class类的实例,只有jvm有该权限,一般有三种方式可以获得:

(1)直接通过类名.Class的方式得到。

Class<User> userClass1 = User.class;

(2)通过对象的getClass()方法获取,这个使用的少,比如给你个Object类型,我们不知道obj具体是什么类型的时候才用此方法。

User user = new User();
Class userClass2 = user.getClass();

(3)通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常。

Class userClass3=Class.forName("cn.goktech.test.User");

注:每一个类只对应一个Class实例对象,不能产生多个。

2.“镜像”操作

创建实例(new Instance())
无参构造方法创建该类的实例

 Class userClass = Class.forName("cn.goktech.test.User");
//   利用反射对象创建实例
    Object o = userClass.newInstance();
    User user1 = (User) o;

带参构造方法创建实例

Constructor c2 = userClass.getDeclaredConstructor(int.class, int.class);
c2.setAccessible(true); //访问权限设置为:可访问
Object o1 = c2.newInstance(11, 22);
User user2 = (User) o1;

字段操作(set(),get())

Class userClass = User.class;
        try {
            User user1  = (User) userClass.newInstance();//获取类的实例
//            获取字段
            Field a = userClass.getDeclaredField("a");
            a.setAccessible(true);
//            获取指定对象的属性值,获取的是user1中的a属性
            System.out.println(a.get(user1));
//            设置指定属性值
            a.set(user1,11);
            System.out.println(a.get(user1));

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

方法操作(invoke())

Class userClass = User.class;
        try {
            User user = (User) userClass.newInstance();
            Method add = userClass.getDeclaredMethod("add", int.class, int.class);
            add.setAccessible(true);//取消属性的访问权限控制,即使private 属性也可以进行访问
//            执行方法:指定对象、参数
            Object sum = add.invoke(user,3,5);
            System.out.println(sum);

getDeclaredMethods(),该方法是获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法。

3.代理模式

设计模式中有一个设计原则是开闭原则
开闭原则明确要求软件应该实现对扩展开放,对修改关闭

静态代理和动态代理:
代理模式可以有两种实现的方式:一种是静态代理,另一种是动态代理。

如果在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制都是通过动态代理实现的。

静态代理

用户功能模块,现在希望新增功能:在对用户的相关操作的前后都添加一些其他操作,根据开闭原则,不能动源码,那么便可以用静态代理模式实现。

使用静态代理带来的问题:
每一个代理类只能为一个接口服务,那么如果有多个接口必然需要多个代理类与之对应,但是这样一来程序开发中必然会产生过多的代理,给以后代码的升级维护带来麻烦。

public class UserDaoProxy implements UserDao{

    private UserDaoImpl impl;//实际业务类

    public UserDaoProxy(UserDaoImpl impl) {
        this.impl = impl;
    }

    @Override
    public int insert(User user) {
        System.out.println("准备插入新数据...");//前置功能拓展
        int count = impl.insert(new User());
        System.out.println("插入完毕!");//后置拓展功能
        return count;
    }

    @Override
    public User getById(int id) {
        System.out.println("即将查询...");
        User user = impl.getById(1001);
        System.out.println("查询完毕!");
        return user;
    }
}

动态代理

动态代理可以分为2种( JDK的动态代理和CGLIB的动态代理):
1、JDK的动态代理依赖具体的接口,即需要被代理类有对应的接口类型,如果一个被代理类没有实现接口,则不能使用JDK的动态代理;且该方法需要实现InvocationHandler接口。
2、CGLIB的动态代理不依赖具体的接口,功能更加强大。即被代理类可以是一个没有接口的类,CGLIB方式需要实现MethodInterceptor接口。

JDK动态代理

主要用到两个方法:
1、java.lang.reflect.Proxy
作用: 调用其静态的newProxyInstance(类加载器,被代理实例接口类型,处理器接口实例)来动态的生成代理类和对象
2、java.lang.reflect.InvocationHandler(处理器接口)
作用:
(1)可以通过其提供的invoke方法实现对真实角色的代理访问,并其中添加想要实现的额外功能。
(2)每次通过Proxy生成的代理类对象时,都要指定相对应的处理器对象。

//处理器接口实例
public class UserJdkProxyHandler implements InvocationHandler {

    private UserDaoImpl userDaoImpl;//实际业务类

    public UserJdkProxyHandler(UserDaoImpl userDaoImpl) {
        this.userDaoImpl = userDaoImpl;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object obj = null;
        System.out.println("动态代理:前置功能增强!!!");
        obj = method.invoke(userDaoImpl, args);
        System.out.println("动态代理:后置功能增强!!!");
        return obj;
    }
}
public class JdkProxyTest {
    public static void main(String[] args) {
        UserDaoImpl impl = new UserDaoImpl();
        UserJdkProxyHandler handler = new UserJdkProxyHandler(impl);

       UserDao proxy= (UserDao) Proxy.newProxyInstance(
                JdkProxyTest.class.getClassLoader(), //类加载器
                new Class[]{UserDao.class},          //被代理的接口
                handler);                            //处理器接口实例
       proxy.insert(new User());
       proxy.getById(1001);
    }
}

获取字段(获取public权限的字段)

//        获取字段(获取public字段)
        Field[] fields = userClass1.getFields();
        for (Field f:fields){
            System.out.println(f.getName());
        }

获取所有字段

// 获取所有字段
        Field[] declaredFields = userClass1.getDeclaredFields();
        for (Field f:declaredFields){
            System.out.println(f.getName());
        }

获取指定字段

//       获取指定字段
        try {
            Field aField = userClass1.getDeclaredField("a");
            System.out.println(aField.getName());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

获取所有方法

//       获取所有方法
        Method[] declaredMethods = userClass1.getDeclaredMethods();
        for (Method m:declaredMethods){
            System.out.println(m.getName());
        }

获取方法(公有权限)

//       获取方法(公有权限)
        Method[] methods = userClass1.getMethods();
        try {
            Method method = userClass1.getDeclaredMethod("add", int.class, int.class);//add()是private权限
            System.out.println(method.getName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

获取构造(公有权限)

//        获取构造(公有权限)
        Constructor<?>[] constructors = userClass1.getConstructors();

获取所有构造

//        获取所有构造
        Constructor<?>[] declaredConstructors = userClass1.getDeclaredConstructors();
        for (Constructor c:declaredConstructors){
            System.out.println(c.getName());
        }

获取指定构造

//        获取指定构造
        try {
            Constructor declaredConstructor = userClass1.getDeclaredConstructor(int.class, int.class);//获取双参构造
            System.out.println(declaredConstructor.getName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值