学习笔记:java反射和动态代理

动态代理

直观的讲:

​ 比如需要增加功能,进入源代码进行修改叫:侵入式修改,可能会导致原有的代码无法运行

​ 在不修改原有的代码并添加新的功能,就需要寻找一个代理来执行添加的新功能:无侵入式修改代码,添加新的功能

最终,调用者需要调用对象中的方法时就要先去调用代理中的方法,代理再去调用对象

代理

  1. 一类对象执行一类方法,对象可以通过代理转移自身的部分职责
  2. 对象有什么方法想要被代理,代理就需要有相对的方法
  3. 需要代理的对象得提供相对应的接口,接口内带有需要被代理的方法,对象和代理需要实现同一个接口

创建一个代理对象

java.lanf.reflect.Proxy类:提供了为代理产生对象的方法


public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  
// 参数1:用于指定用那个类加载器,来加载生成的代理类
// 参数2:指定接口,这些接口用于指定生成的代理存在那些方法
// 参数3:用于指定生成的代理需要干那些事情

类加载器:把当前类加载到内存的

动态代理的例子

  1. 创建一个需要被代理的类:一个大明星只需要唱歌跳舞,场地准备和收取门票的事情交给负责代理的经纪公司

    public class BigStar implements Star{
        private String name;
    
        public BigStar() {
    
        }
    
        public BigStar(String name) {
            this.name = name;
        }
        @Override
        public String sing(String name) {
            System.out.println("正在唱歌:"+name);
            return "唱完了";
        }
        @Override
        public void dance() {
            System.out.println("正在跳舞");
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
  2. 负责代理的经纪公司需要派出一名经纪人,这个经纪人要求一样会唱歌跳舞,所以需要一个有着唱歌跳舞方法的接口,这个接口是代理对象制作代理方法的依据

    public interface Star {
        public String sing(String name);
        public void dance();
    }
    
    
  3. 代理公司给出了一个代理对象,对象内有一个静态方法,从此用户需要通过先调用代理对象的代理方法才能运行有新功能的 大明星对象

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 类的作用:
     *       创建一个代理
     */
    public class ProxyUtil {
        // 方法的作用 给BigStar对象创建一个代理
    
        /**
         *
         * 形参:   被代理的对象
         * @return 方法的返回值是代理的对象,返回接口即可
         */
    
        // 1. 方法是获取代理的对象的,用户想要获取BigStar对象就要ProxyUtil.createProxy(BigStar),返回的值就是代理的对象:代理对象 = ProxyUtil.createProxy(BigStar);
        // 2. 再用代理的对象调用BigStar里的sing方法:代理对象.sing(“name");
        public static Star createProxy(BigStar bigStar) {
            Star star = (Star) Proxy.newProxyInstance
                    // 参数1:用于指定用那个类加载器,来加载生成的代理类 :当前的类
                            (ProxyUtil.class.getClassLoader(),
                                    // 参数2:指定接口,这些接口用于指定生成的代理存在那些方法
                                    new Class[]{Star.class},
                                    // 参数3:用于指定生成的代理需要干那些事情
                                    //InvocationHandler 是一个接口,再形参中要写他的实现类(匿名内部类)
                                    new InvocationHandler() {
                                        @Override
                                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                            // 要添加的新的功能写再这里
                                            /**
                                             invoke方法的三个参数的作用分别是
                                             proxy: 被代理的对象
                                             method: 要运行的方法
                                             args: 调用要运行的方法时传递的实参
                                             */
     
                                            // 反射获取到的方法名是字符串,做一个判断,如果调用的sing方法
                                            if ("sing".equals(method.getName())) {
                                                System.out.println("这里是新增的方法1:准备话筒,收取门票");
                                            }else if ("dance".equals(method.getName())) {
                                                System.out.println("这里是新增的方法1:准备话筒,收取门票");
                                            }
                                            // 返回被代理对象BigDance的方法的输出结构
                                            return method.invoke(bigStar,args);
                                        }
                                    }
                            );
            return star;
        }
    
    }
    
    
  4. 用户调取 对象

    public class Text {
        public static void main(String[] args) {
            BigStar bigStar = new BigStar("cxk");
            Star proxy = ProxyUtil.createProxy(bigStar);
            proxy.sing("及你太忙");
            proxy.dance();
        }
    }
    
    

#反射

反射允许对封装类的字段(成员变量 field)、方法(成员方法 method)和构造函数(构造方法 constructor)的信息进行编程访问

获取class 字节码对象

获取class对象一共有三种方法

1. Class.forName("全类名")// 全类名:包名.类名  // 常用
2. 类名.class; // 多作为参数传递
3. 对象.getClass(); // 当已经创建了该类的对象时 使用

###获取构造方法Constructor

Class类中用于获取构造方法 的方法

Constructor<>[] getConstructors(); 返回所有 公共构造方法 的对象的数组 只能获取public
Constructor<>[] getDeclaredConstructors();	返回所有 构造方法 对象的数组 
Constructor<T> getConstructor(Class<?>...parameterTypes); 返回单个公共构造方法对象 只能获取public
Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes); 返回单个构造方法对象
// 参数:和需要获取的构造方法的参数保持一致
比如我需要获取的类里面有构造方法 
public student(String name);
那获取就需要
Class clazz = Class.forName("student");
Constructor con = clazz.getDeclaredConstructor(String.class);

Constructor 类中用于创建对象的方法

T newInstance(Object... initargs): 根据指定的构造方法创建对象
setAccessible(boolean flag): 设置为true,表示取消访问检查(取消权限)

获取了构造方法后

获取权限修饰符
private student(String name);
///
Class clazz = Class.forName("student");
Constructor con = clazz.getDeclaredConstructor(String.class);
// 获取权限修饰符
int modifiers = con4.getModifi
获取名字

就是类名

获取形参
private student(String name);
///
Class clazz = Class.forName("student");
Constructor con = clazz.getDeclaredConstructor(String.class);
// 获取构造方法的参数(一般用在私有身上)
Parameter[] parameters = con.getParameters();
创建对象
private student(String name);
///
Class clazz = Class.forName("student");
Constructor con = clazz.getDeclaredConstructor(String.class);
// 利用构造方法创建对象(创建共有私有都可以用)
//创建私有要有额外步骤
con.setAccessible(true); // 暴力反射:临时取消权限检验
student student =(student)con.newInstance("zhangsan") // 传参要和构造方法一致

获取字段(成员变量)

Class类中用于获取成员变量的方法

Field[] getFields(): 返回所有公共成员变量对象的数组
Field[] getDeclaredFields(): 返回所有成员变量对象的数组
Field getField(String name): 返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象 

Field 类中用于创建对象的方法

void set(Object obj,Object value):赋值
Object get(Object obj):获取值
获取名字
// 获取成员变量
class student {public String name; public int age; }
///
Class clazz = Class.forName("student");
// 获取全部
Field[] fields = clazz.getDeclaredFields();
// 获取单一的
Field field = clazz.getDeclaredField(age);
获取权限修饰符

class student {public String name; public int age; }
///
Class clazz = Class.forName("student");
Field field = clazz.getDeclaredField(age);

// 获取权限修饰符
int modifiers = field.getModifiers();
获取数据类型
class student {public String name; public int age; }
///
Class clazz = Class.forName("student");
Field field = clazz.getDeclaredField(age);

// 获取数据类型
Class<?> type = field.getType();
成员变量的值

获取值和对象有关(已经被创建并赋值了)

class student {public String name; public int age; } // 有构造方法
student s = new student("张三",19);
//
Class clazz = Class.forName("student");
Field field = clazz.getDeclaredField(age);
// 如果变量是私有的,则需要
field.setAccessible(true);
int value = (int)field.get(s); // 此处抛出一个异常 
修改对象的值
class student {public String name; public int age; } // 有构造方法
student s = new student("张三",19);
//
Class clazz = Class.forName("student");
Field field = clazz.getDeclaredField(age);
// 修改对象的值
field.set(s,23); // 传入对象和要修改的值,这里19--> 23

获取成员方法

Class类中用于获取成员方法的方法

Method[] getMethods();返回所有公共成员方法对象的数组
Method[] getDeclaredMethods(); 返回所有成员方法对象的数组
Method getMethod(String name,Class<?>...parameterTypes);返回单个公共成员方法的对象
Method getDeclaredMethod(String name,Class<?>...parameterTypes);返回单个成员方法的对象
// 参数1:方法的名字
// 参数2:方法的参数的类型(方法重载)

Method类中用于创建对象的方法

Object invoke(Object obj,Object...args):运行方法
/*
	参数1: 用obj对象调用该方法
	参数2: 调用方法的传递参数(如果没有就不写)
	返回值: 方法的返回值(没有则返回null)
*/
获取方法
class student{
    // get、set、tostring方法都有
    .....
    public void sleep() {
        System.out.println("睡觉");
    }

    public void eat (String something) {
        System.out.println("在吃"+ something);
    }
    .....
}

Class clazz = Class.forName("student");
// 获取所有方法(getMethods 会获取到父类的所有public方法)
Method[] methods= clazz.getDeclaredMethods(); // 不能获取父类的
// 获取单个方法
Method method= clazz.getDeclaredMethod("eat",String.class);
获取方法修饰符
class student{
    // get、set、tostring方法都有
    .....
    public void sleep() {
        System.out.println("睡觉");
    }

    public void eat (String something) {
        System.out.println("在吃"+ something);
    }
    .....
}

Class clazz = Class.forName("student");
Method method= clazz.getDeclaredMethod("eat",String.class);
// 获取方法的修饰符
int modifiers = method.getModifiers();
获取方法的名字
class student{
    // get、set、tostring方法都有
    .....
    public void sleep() {
        System.out.println("睡觉");
    }

    public void eat (String something) {
        System.out.println("在吃"+ something);
    }
    .....
}

Class clazz = Class.forName("student");
Method method= clazz.getDeclaredMethod("eat",String.class);
// 获取方法名字
String name = m.getName();
获取方法的形参
class student{
    // get、set、tostring方法都有
    .....
    public void sleep() {
        System.out.println("睡觉");
    }

    public void eat (String something) {
        System.out.println("在吃"+ something);
    }
    .....
}

Class clazz = Class.forName("student");
Method method= clazz.getDeclaredMethod("eat",String.class);
//获取方法的形参
Parameter[] parameters = method.getParameters();
// getParameterCount 获取参数数量
// getParameterTypes 获取参数类型
获取方法抛出的异常
class student{
    // get、set、tostring方法都有
    .....
    public void sleep() {
        System.out.println("睡觉");
    }

    public void eat (String something) throw IOException,NullPointException{
        System.out.println("在吃"+ something);
    }
    .....
}

Class clazz = Class.forName("student");
Method method= clazz.getDeclaredMethod("eat",String.class);
// 获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();

方法运行并获取返回值(有就获取到了)
class student{
    // get、set、tostring方法都有
    .....
    public void sleep() {
        System.out.println("睡觉");
    }

    public String eat (String something) {
        System.out.println("在吃"+ something);
        return "好吃";
    }
    .....
}

Class clazz = Class.forName("student");
Method method= clazz.getDeclaredMethod("eat",String.class);
// 运行方法
// 参数1: 用obj对象调用该方法
// 参数2: 调用方法的传递参数(如果没有就不写)
// 方法的返回值,void就不写

// 创建一个新对象
student s = new student();
// 调用eat 方法
// 参数1表示方法的调用者,参数2方法传入的实际参数
String result = (String)method.invoke(s,"汉堡")

反射的作用

  1. 获取一个类里的所有信息,获取后再执行其他的业务逻辑
  2. 结合配置文件,动态创建对象并调用方法
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值