Java学习笔记===》29.反射&动态代理

反射&动态代理

1.反射

(1)反射的概述

①什么是反射?

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

②反射的作用

​ 能够获取类里面的一切信息
在这里插入图片描述

(2)获取Class的三种方式

①Class.forName(“全类名”);

②类名.class

③对象.getClass();

**源代码阶段:**以.java/.class结尾的文件就是源代码,在这个阶段用Class.for Name(“全类名”);方法获取Class

**加载阶段:**将Class文件加载到内存的阶段就是加载阶段,这个阶段用类名.class获取Class

**运行阶段:**创建此类的对象的阶段就是运行阶段,这个阶段用对象.getClass();方法获取Class

package com_13_Reflect._01ReflectTest01;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException {
        /*(2)获取Class的三种方式
             ①Class.forName("全类名");
             ②类名.class
             ③对象.getClass();
*/


        //1.第一种方式
        //全类名:包名+类名
        //最为常用
        Class clazz1 = Class.forName("com_13_Reflect._01ReflectTest01.Student");

        //第二种方式
        //一半当作参数传递,比如Synchronized(Student.class){}
        Class<Student> clazz2 = Student.class;

        //3.第三种方式
        //当有了这个类的实例对象,才可以使用
        Student s1 = new Student();
        Class clazz3 = s1.getClass();
    }
}

(3)反射获取构造方法=》Constructor

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

方法名称说明
Constructor <?> [] getConstructors ( )返回所有公共构造方法对象的数组
Constructor <?> [] getDeclaredConstructors ( )返回所有构造方法对象的数组
Constructor <?> [] getConstructor (Class< ? >…paramentTypes )返回单个公共构造方法对象
Constructor<?>[]getDeclaredConstructor(Class<?>…paramentTypes )返回单个构造方法对象

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

方法名称说明
T newInstance (Object … initargs)根据指定的构造方法创建对象
setAccessible(boolean flag)设置为true,表示取消访问检查
//自己加一些各种修饰符修饰的构造方法
package com_13_Reflect._02ReflectTest02;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name){
        this.name = name;
    }

    protected Student(int age){
        this.age = age;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
package com_13_Reflect._02ReflectTest02;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
*Class类中用于获取构造方法的方法
| 方法名称                                                     | 说明                           |
| ------------------------------------------------------------ | ------------------------------ |
| Constructor  <?>  []  getConstructors ( )                    | 返回所有公共构造方法对象的数组 |
| Constructor  <?>  []  getDeclaredConstructors ( )            | 返回所有构造方法对象的数组     |
| Constructor  <?>  []  getConstructor (Class< ? >...paramentTypes ) | 返回单个公共构造方法对象       |
| Constructor<**?**>[]getDeclaredConstructor(Class<?>..paramentTypes ) | 返回单个构造方法对象           |

Constructor类中用于创建对象的方法
| 方法名称                            | 说明                         |
| ----------------------------------- | ---------------------------- |
| T newInstance (Object ... initargs) | 根据指定的构造方法创建对象   |
| setAccessible(boolean flag)       | 设置为true,表示取消访问检查 |
*/

        //1.获取Class字节码文件的对象
        Class<?> clazz = Class.forName("com_13_Reflect._02ReflectTest02.Student");

        System.out.println("=============================================================");

        //2.获取构造方法
        //Constructor  <?>  []  getConstructors ( )                    | 返回所有公共构造方法对象的数组 |
        Constructor<?>[] cons1 = clazz.getConstructors();
        for (Constructor<?> con : cons1) {
            System.out.println(con);
        }

        System.out.println("=============================================================");

        //Constructor  <?>  []  getDeclaredConstructors ( )            | 返回所有构造方法对象的数组     |
        Constructor<?>[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor<?> con : cons2) {
            System.out.println(con);
        }

        System.out.println("=============================================================");

        //Constructor  <?>  []  getConstructor (Class< ? >...paramentTypes ) | 返回单个公共构造方法对象       |
        Constructor<?> cons3 = clazz.getConstructor();
        System.out.println(cons3+"没有参数的构造");
        Constructor<?> cons4 = clazz.getDeclaredConstructor(String.class);
        System.out.println(cons4+"String类型的参数");
        Constructor<?> cons5 = clazz.getDeclaredConstructor(int.class);
        System.out.println(cons5+"int类型的参数");
        Constructor<?> cons6 = clazz.getDeclaredConstructor(String.class,int.class);
        System.out.println(cons6+"String类型的参数和int类型的参数");

        //利用反射获取构造方法的权限修饰符
        int modifiers = cons4.getModifiers();
        System.out.println(modifiers);

        //利用反射获取参数类型
        Parameter[] parameters = cons4.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //利用反射创建对应构造方法的对象,但如果这个构造方法是私有的,不能直接创建
        //先利用 setAccessible(boolean flag)| 设置为true,表示取消访问检查 |
        //也叫暴力反射:表示临时取消权限修饰符的校验
        cons6.setAccessible(true);
        Student stu = (Student) cons6.newInstance("张三", 23);
        System.out.println(stu);


        System.out.println("=============================================================");

        //Constructor<**?**>[]getDeclaredConstructor(Class<?>..paramentTypes ) | 返回单个构造方法对象
        Constructor<?> cons7 = clazz.getDeclaredConstructor();
        System.out.println(cons7);


    }
}

/*运行结果
=============================================================
public com_13_Reflect._02ReflectTest02.Student()
public com_13_Reflect._02ReflectTest02.Student(java.lang.String,int)
public com_13_Reflect._02ReflectTest02.Student(java.lang.String)
=============================================================
public com_13_Reflect._02ReflectTest02.Student()
public com_13_Reflect._02ReflectTest02.Student(java.lang.String,int)
protected com_13_Reflect._02ReflectTest02.Student(int)
public com_13_Reflect._02ReflectTest02.Student(java.lang.String)
=============================================================
public com_13_Reflect._02ReflectTest02.Student()没有参数的构造
public com_13_Reflect._02ReflectTest02.Student(java.lang.String)String类型的参数
protected com_13_Reflect._02ReflectTest02.Student(int)int类型的参数
public com_13_Reflect._02ReflectTest02.Student(java.lang.String,int)String类型的参数和int类型的参数
1
java.lang.String arg0
Student{name = 张三, age = 23}
=============================================================
public com_13_Reflect._02ReflectTest02.Student()
*/

(4)反射获取成员变量=》Field

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

方法名称说明
Field [] getFie’lds ( );返回所有公共成员变量对象的数组
Field [] getDeclaredFields ( );返回所有成员变量对象的数组
Field getField (String name);返回单个公共成员变量对象
Field getDeclaredField (String name)返回单个成员变量对象

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

方法名称说明
void set (Object obj, Object value )赋值
Object get(Object obj)获取值
package com_13_Reflect._03ReflectTest03;

public class Student {
    private String name;
    private int age;
    public String gender;

    
package com_13_Reflect._03ReflectTest03;

import java.lang.reflect.Field;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
/*Class类中用于获取成员变量的方法
| 方法名称                             | 说明                           |
| ------------------------------------ | ------------------------------ |
| Field  []   getFileds  ( );          | 返回所有公共成员变量对象的数组 |
| Field  []  getDeclaredFields  ( );   | 返回所有成员变量对象的数组     |
| Field  getFiled (String name);       | 返回单个公共成员变量对象       |
| Field getDeclaredField (String name) | 返回单个成员变量对象           |

Filed类中用于创建对象的方法
| 方法名称                             | 说明   |
| ------------------------------------ | ------ |
| void set (Object obj, Object value ) | 赋值   |
| Object get(Object obj)               | 获取值 |

*/
        //1.获取Class字节码文件对象
        Class<?> clazz = Class.forName("com_13_Reflect._03ReflectTest03.Student");

        System.out.println("=============================================================");

        //2.获取成员变量的对象
        //Field  []   getFileds  ( );          | 返回所有公共成员变量对象的数组
        Field[] fields1 = clazz.getFields(); //获取公共的成员变量
        for (Field field : fields1) {
            System.out.println(field);
        }

        System.out.println("=============================================================");

        //Field  []  getDeclaredFields  ( );   | 返回所有成员变量对象的数组     |
        Field[] fields2 = clazz.getDeclaredFields();  //获取所有的成员变量
        for (Field field : fields2) {
            System.out.println(field);
        }

        System.out.println("=============================================================");

        // Field  getFiled (String name);       | 返回单个公共成员变量对象       |
        Field field1 = clazz.getField("gender");//获取单个的成员变量
        System.out.println(field1);

        System.out.println("=============================================================");

        //Field getDeclaredField (String name) | 返回单个成员变量对象           |
        Field name = clazz.getDeclaredField("name");
        Field age = clazz.getDeclaredField("age");
        Field gender = clazz.getDeclaredField("gender");

        System.out.println(name);
        System.out.println(age);
        System.out.println(gender);

        System.out.println("=============================================================");

        //获取成员变量的权限修饰符
        int modifiers1 = name.getModifiers();
        int modifiers2 = age.getModifiers();
        int modifiers3 = gender.getModifiers();

        System.out.println(modifiers1);
        System.out.println(modifiers2);
        System.out.println(modifiers3);

        System.out.println("=============================================================");

        //获取成员变量名
        String name1 = name.getName();
        System.out.println(name1);
        String name2 = age.getName();
        System.out.println(name2);

        System.out.println("=============================================================");

        //获取成员变量类型
        Class<?> type1 = name.getType();
        System.out.println(type1);
        Class<?> type2 = age.getType();
        System.out.println(type2);

        System.out.println("=============================================================");

        //获取成员变量记录的值
        //Object get(Object obj)               | 获取值 |
        Student stu = new Student("张三",23,"男");
        name.setAccessible(true); //不管是构造方法还是成员变量,只要修饰符不是公共的,就必须调用此方法临时改变权限
        String value = (String) name.get(stu);
        System.out.println(value);

        System.out.println("=============================================================");

        //利用反射修改成员变量记录的值
        //void set (Object obj, Object value ) | 赋值   |
        //参数一:要修改的时哪个对象的值
        //参数二:修改后的值
        name.set(stu,"lisi");
        System.out.println(stu);

    }
}
/*运行结果
=============================================================
public java.lang.String com_13_Reflect._03ReflectTest03.Student.gender
=============================================================
private java.lang.String com_13_Reflect._03ReflectTest03.Student.name
private int com_13_Reflect._03ReflectTest03.Student.age
public java.lang.String com_13_Reflect._03ReflectTest03.Student.gender
=============================================================
public java.lang.String com_13_Reflect._03ReflectTest03.Student.gender
=============================================================
private java.lang.String com_13_Reflect._03ReflectTest03.Student.name
private int com_13_Reflect._03ReflectTest03.Student.age
public java.lang.String com_13_Reflect._03ReflectTest03.Student.gender
=============================================================
2
2
1
=============================================================
name
age
=============================================================
class java.lang.String
int
=============================================================
张三
=============================================================
Student{name = lisi, age = 23, gender = 男}
*/

(5)反射获取成员方法

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

方法名称说明
Metrhod [] getMethods()返回所有公共成员方法对象的数组,包括继承的
Metrhod [] getDeclaredMethods()返回所有公共成员方法对象的数组,不包括继承的
Method getMethod(String name,Class<?>…paramentTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name,Class<?>…paramentTypes)返回单个成员方法对象

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

方法名称说明
Object invoke (Object obj,Object…args)运行方法
参数一:用obj对象调用该方法 参数二:调用方法传递的参数(如果没有就不写)返回值:方法的返回值(如果没有就不写)
package com_13_Reflect._04ReflectTest04;

import java.io.IOException;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }

    public void sleep() throws NullPointerException{
        System.out.println("睡觉");
    }

    private void eat(String sth) throws IOException {
        System.out.println("在吃"+sth);
    }

    private String eat(String sth,int a) throws NumberFormatException, IOException,NullPointerException{
        System.out.println("在吃"+sth);
        return "方法的返回值是String类型的";
    }
}
package com_13_Reflect._04ReflectTest04;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class  ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
/*Class类中获取成员方法的方法
| 方法名称                                                     | 说明                                         |
| ------------------------------------------------------------ | -------------------------------------------- |
| Metrhod [] getMethods()                                      | 返回所有公共成员方法对象的数组,包括继承的   |
| Metrhod [] getDeclaredMethods()                              | 返回所有成员方法对象的数组,不包括继承的 |
| Method getMethod(String name,Class<?>...paramentTypes)       | 返回单个公共成员方法对象                     |
| Method getDeclaredMethod(String name,Class<?>...paramentTypes) | 返回单个成员方法对象                         |

Method类中用于创建对象的方法
| 方法名称                                                     | 说明                                   |
| ------------------------------------------------------------ | -------------------------------------- |
| Object invoke (Object obj,Object...args)                  | 运行方法                               |
| 参数一:用obj对象调用该方法  参数二:调用方法传递的参数(如果没有就不写) | 返回值:方法的返回值(如果没有就不写) |*/

        //1.获取Class字节码文件的对象
        Class<?> clazz = Class.forName("com_13_Reflect._04ReflectTest04.Student");

        System.out.println("=============================================================");

        //2.Metrhod [] getMethods()    | 返回所有公共成员方法对象的数组,包括继承的   |
        Method[] methods1 = clazz.getMethods(); //只能获取public修饰的成员方法,可以获取继承父类的public修饰的成员方法
        for (Method method : methods1) {
            System.out.println(method);
        }

        System.out.println("=============================================================");

        //3.Metrhod [] getDeclaredMethods()     | 返回所有成员方法对象的数组,不包括继承的 |
        Method[] methods2 = clazz.getDeclaredMethods(); //获取本类里面所有的成员方法,包括私有的
        for (Method method : methods2) {
            System.out.println(method);
        }

        System.out.println("=============================================================");

        //Method getMethod(String name,Class<?>...paramentTypes)       | 返回单个公共成员方法对象
        Method method3 = clazz.getDeclaredMethod("eat", String.class);//获取指定的单一方法
        System.out.println(method3);
        Method method4 = clazz.getDeclaredMethod("eat", String.class, int.class);

        System.out.println("=============================================================");

        //获取方法的修饰符
        int modifiers = method4.getModifiers();
        System.out.println(modifiers);

        System.out.println("=============================================================");

        //获取方法的名字
        String methodName = method3.getName();
        System.out.println(methodName);

        System.out.println("=============================================================");

        //获取方法的形参
        Parameter[] parameters = method4.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        System.out.println("=============================================================");

        //获取方法的形参类型
        Class<?>[] parameterTypes = method3.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println(parameterType);
        }

        System.out.println("=============================================================");


        //获取方法抛出的异常
        Class<?>[] exceptionTypes = method4.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        System.out.println("=============================================================");

        //运行成员方法
        //Object invoke (Object obj,Object...args)        运行方法   |
        //参数一:用obj对象调用该方法
        //参数二:调用方法传递的参数(如果没有就不写)
        //返回值:方法的返回值(如果没有就不写)

        Student s = new Student("张三",23);
        //参数一:方法的调用者
        //参数二:调用方法时时机传递的参数
        method4.setAccessible(true);
        Object result = method4.invoke(s, "饺子", 2);
        System.out.println(result);


    }
}
/*运行结果
=============================================================
public java.lang.String com_13_Reflect._04ReflectTest04.Student.getName()
public java.lang.String com_13_Reflect._04ReflectTest04.Student.toString()
public void com_13_Reflect._04ReflectTest04.Student.sleep() throws java.lang.NullPointerException
public void com_13_Reflect._04ReflectTest04.Student.setName(java.lang.String)
public void com_13_Reflect._04ReflectTest04.Student.setAge(int)
public int com_13_Reflect._04ReflectTest04.Student.getAge()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
=============================================================
public java.lang.String com_13_Reflect._04ReflectTest04.Student.getName()
public java.lang.String com_13_Reflect._04ReflectTest04.Student.toString()
public void com_13_Reflect._04ReflectTest04.Student.sleep() throws java.lang.NullPointerException
public void com_13_Reflect._04ReflectTest04.Student.setName(java.lang.String)
private void com_13_Reflect._04ReflectTest04.Student.eat(java.lang.String) throws java.io.IOException
private java.lang.String com_13_Reflect._04ReflectTest04.Student.eat(java.lang.String,int) throws java.lang.NumberFormatException,java.io.IOException,java.lang.NullPointerException
public void com_13_Reflect._04ReflectTest04.Student.setAge(int)
public int com_13_Reflect._04ReflectTest04.Student.getAge()
=============================================================
private void com_13_Reflect._04ReflectTest04.Student.eat(java.lang.String) throws java.io.IOException
=============================================================
2
=============================================================
eat
=============================================================
java.lang.String arg0
int arg1
=============================================================
class java.lang.String
=============================================================
class java.lang.NumberFormatException
class java.io.IOException
class java.lang.NullPointerException
=============================================================
在吃饺子
方法的返回值是String类型的
*/

(6)反射综合练习

反射的作用以及应用场景:

★获取一个类里所有的信息,获取到了之后,再执行其他的业务逻辑

★结合配置文件,动态的创建对象并调用方法

①对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去

package com_13_Reflect._05ReflectTest05;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;

public class ReflectTest {
    public static void main(String[] args) throws IOException, IllegalAccessException {
        /*
        * 对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
        * */

        Student s = new Student("huihui",18,"女","蹦迪");
        Teacher t= new Teacher("kinbow",1000000000);

        saveObject(s);
    }

    private static void saveObject(Object obj) throws IOException, IllegalAccessException {
        //1.获取字节码文件的对象
        Class<?> clazz = obj.getClass();

        //2.创建IO流
        BufferedWriter bw = new BufferedWriter(new FileWriter("Java_based\\study\\src\\com_13_Reflect\\_05ReflectTest05\\a.txt"));

        //3.获取所有的成员变量
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            //获取成员变量的名字
            String name = field.getName();
            //获取成员变量的值
            Object value = field.get(obj);
            //写出数据
            bw.write(name+"="+value);
            bw.newLine();
        }
        bw.close();
    }
}

②反射可以跟配置文件结合的方式,动态的创建对象,并调用方法

配置文件

//如果想更换对象,只需要修改配置文件就可以了
classname=com_13_Reflect._06ReflectTest06.Student
method=study
package com_13_Reflect._06ReflectTest06;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        /*
        * ②反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
        * */

        //1.读取配置文件中的信息
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream("Java_based\\study\\src\\com_13_Reflect\\_06ReflectTest06\\prop.properties");
        prop.load(fis);

        //2.h获取全类名和方法名
        String className = (String) prop.get("classname");
        String methodName = (String) prop.get("method");

        System.out.println(className);
        System.out.println(methodName);

        //3.利用反射创建对象并运行方法
        Class<?> clazz = Class.forName(className);

        //获取构造方法
        Constructor  con = clazz.getDeclaredConstructor();

        //创建对象
        Object o = con.newInstance();

        System.out.println(o);

        //获取成员方法并运行
        Method declaredMethod = clazz.getDeclaredMethod(methodName);
        declaredMethod.setAccessible(true);

        declaredMethod.invoke(o);

    }
}

(7)反射小结

①反射的作用

​ ★获取任意一个类中的所有信息

​ ★结合配置文件动态创建对象

②获得字节码文件对象的三种方式

​ ★Class.forName(“全类名”);

​ ★类名.class

​ ★对象.getClass();

③如何获取构造方法、成员方法、成员变量

​ ★get:获取 ★set:设置

​ ★Constructor:构造方法 ★Parameter:参数

​ ★Field:成员变量 ★Modifiers:修饰符

​ ★Method:方法 ★Declared:所有的

2.动态代理

(1)什么是动态代理

​ 在不改动原本代码的基础上增加新的功能,就需要动态代理

动态代理:无侵入式的给代码增加额外的功能

①为什么需要动态代理

​ 对象如果嫌身上的事太多的话,可以通过代理来转移部分职责

②代理是什么样子的

​ 对象有什么方法想被代理,代理就一定要有对应的方法

③方法需要代理的时机

​ 先将需要代理的方法抽取成接口,那么在接口里面的方法,就是对象需要代理的方法,对象和代理都需要先实现中间接口

​ Java通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法

(2)如何给Java对象创建一个代理对象

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

public static Object newProxyInstance(ClassLoader loader,Class<?> interfaces,InvocationHandler h){
    参数一:用于指定那个类加载器,去加载生成的代理类
    参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法
    参数三:用来指定生成的代理要干什么事情
}
package com_14_DynamicProxy._01DynamicProxyTest01;

public class BigStar implements Star {
    private String name;

    public BigStar() {
    }

    public BigStar(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "BigStar{name = " + name + "}";
    }

    @Override
    public void dance(){
        System.out.println(this.name+"正在跳舞");
    }

    @Override
    public String sing(String name){
        System.out.println(this.name+"正在唱"+name);
        return "谢谢";
    }
}

//接口
package com_14_DynamicProxy._01DynamicProxyTest01;

public interface Star {
    //我们可以把所有想要被代理的方法定义在接口当中


    public abstract void dance();


    public abstract String sing(String name);
}


//
package com_14_DynamicProxy._01DynamicProxyTest01;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
*
* 这个类的作用:
*       创建一个代理
* */
public class ProxyUtil {


    /*
     *
     * 方法的作用:
     *       给一个明星的对象,创建一个代理
     *
     *  形参:
     *       被代理的明星对象
     *
     *  返回值:
     *       给明星创建的代理
     *
     *
     *
     * 需求:
     *   外面的人想要大明星唱一首歌
     *   1. 获取代理的对象
     *      代理对象 = ProxyUtil.createProxy(大明星的对象);
     *   2. 再调用代理的唱歌方法
     *      代理对象.唱歌的方法("只因你太美");
     * */
    public static Star createProxy(BigStar bigStar){
       /* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        参数一:用于指定用哪个类加载器,去加载生成的代理类
        参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
        参数三:用来指定生成的代理对象要干什么事情*/
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类
                new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
                //参数三:用来指定生成的代理对象要干什么事情
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                         * 参数一:代理的对象
                         * 参数二:要运行的方法 sing
                         * 参数三:调用sing方法时,传递的实参
                         * */
                        if("sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");
                        }
                        //去找大明星开始唱歌或者跳舞
                        //代码的表现形式:调用大明星里面唱歌或者跳舞的方法
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;

    }
}
//测试类
package com_14_DynamicProxy._01DynamicProxyTest01;

public class Test {
    public static void main(String[] args) {
        /*
        需求:
            外面的人想要大明星唱一首歌
             1. 获取代理的对象
                代理对象 = ProxyUtil.createProxy(大明星的对象);
             2. 再调用代理的唱歌方法
                代理对象.唱歌的方法("只因你太美");
     */


        //1. 获取代理的对象
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);

        //2. 调用唱歌的方法
        String result = proxy.sing("只因你太美");
        System.out.println(result);

    }
}

(3)额外扩展

动态代理,还可以拦截方法

比如:

​ 在这个故事中,经济人作为代理,如果别人让邀请大明星去唱歌,打篮球,经纪人就增强功能。

​ 但是如果别人让大明星去扫厕所,经纪人就要拦截,不会去调用大明星的方法。

/*
* 类的作用:
*       创建一个代理
* */
public class ProxyUtil {
    public static Star createProxy(BigStar bigStar){
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if("cleanWC".equals(method.getName())){
                            System.out.println("拦截,不调用大明星的方法");
                            return null;
                        }
                        //如果是其他方法,正常执行
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
    }
}

(4) 动态代理的练习

​ 对add方法进行增强,对remove方法进行拦截,对其他方法不拦截也不增强

public class MyProxyDemo1 {
    public static void main(String[] args) {
        //动态代码可以增强也可以拦截
        //1.创建真正干活的人
        ArrayList<String> list = new ArrayList<>();

        //2.创建代理对象
        //参数一:类加载器。当前类名.class.getClassLoader()
        //                 找到是谁,把当前的类,加载到内存中了,我再麻烦他帮我干一件事情,把后面的代理类,也加载到内存

        //参数二:是一个数组,在数组里面写接口的字节码文件对象。
        //                  如果写了List,那么表示代理,可以代理List接口里面所有的方法,对这些方法可以增强或者拦截
        //                  但是,一定要写ArrayList真实实现的接口
        //                  假设在第二个参数中,写了MyInter接口,那么是错误的。
        //                  因为ArrayList并没有实现这个接口,那么就无法对这个接口里面的方法,进行增强或拦截
        //参数三:用来创建代理对象的匿名内部类
        List proxyList = (List) Proxy.newProxyInstance(
                //参数一:类加载器
                MyProxyDemo1.class.getClassLoader(),
                //参数二:是一个数组,表示代理对象能代理的方法范围
                new Class[]{List.class},
                //参数三:本质就是代理对象
                new InvocationHandler() {
                    @Override
                    //invoke方法参数的意义
                    //参数一:表示代理对象,一般不用(了解)
                    //参数二:就是方法名,我们可以对方法名进行判断,是增强还是拦截
                    //参数三:就是下面第三步调用方法时,传递的参数。
                    //举例1:
                    //list.add("阿玮好帅");
                    //此时参数二就是add这个方法名
                    //此时参数三 args[0] 就是 阿玮好帅
                    //举例2:
                    //list.set(1, "aaa");
                    //此时参数二就是set这个方法名
                    //此时参数三  args[0] 就是 1  args[1]"aaa"
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //对add方法做一个增强,统计耗时时间
                        if (method.getName().equals("add")) {
                            long start = System.currentTimeMillis();
                            //调用集合的方法,真正的添加数据
                            method.invoke(list, args);
                            long end = System.currentTimeMillis();
                            System.out.println("耗时时间:" + (end - start));
                            //需要进行返回,返回值要跟真正增强或者拦截的方法保持一致
                            return true;
                        }else if(method.getName().equals("remove") && args[0] instanceof Integer){
                            System.out.println("拦截了按照索引删除的方法");
                            return null;
                        }else if(method.getName().equals("remove")){
                            System.out.println("拦截了按照对象删除的方法");
                            return false;
                        }else{
                            //如果当前调用的是其他方法,我们既不增强,也不拦截
                            method.invoke(list,args);
                            return null;
                        }
                    }
                }
        );

        //3.调用方法
        //如果调用者是list,就好比绕过了第二步的代码,直接添加元素
        //如果调用者是代理对象,此时代理才能帮我们增强或者拦截

        //每次调用方法的时候,都不会直接操作集合
        //而是先调用代理里面的invoke,在invoke方法中进行判断,可以增强或者拦截
        proxyList.add("aaa");
        proxyList.add("bbb");
        proxyList.add("ccc");
        proxyList.add("ddd");

        proxyList.remove(0);
        proxyList.remove("aaa");


        //打印集合
        System.out.println(list);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值