13---Junit单元测试+反射+注解+动态代理

本文详细介绍了Java中的Junit单元测试,包括其背景、概念、使用步骤和常用注解。接着,深入探讨了反射的概念、应用场景和操作步骤,涵盖Class对象、Constructor、Method以及Field的使用。此外,讲解了注解的基本概念、作用、自定义注解及其元注解。最后,讨论了动态代理的原理、好处以及相关API的使用,展示了如何通过反射和动态代理增强代码功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Junit单元测试

1、背景:

​ 在main方法中写代码测试存在的问题:所有代码都写在main方法中,都会运行,我们如果要测试,会执行所有代码,测试效率会变低

2、概念:

单元测试是对部分内容进行测试

Junit是java的一个第三方单元测试框架,其保存在junit.jar中。

PS:第一方:JDK提供的类;第二方:自己写的类;第三方:其他人写的很多类。

​ junit用处:可以对部分代码进行测试

3、Junit的使用步骤
1.定义一个测试类
2.编写测试方法
	测试方法的要求:
		1 必须是public修饰的
        2 返回值必须是void
        3 参数列表必须为空
3.在测试方法里面编写我们要测试的代码
4.在测试方法头上添加一个@Test注解
5.运行测试方法
	5.1运行的方式
 		5.1.1在【测试方法左边】点击绿色三角形,运行一个测试方法
        5.1.2在【测试类的左边】点击绿色三角形,运行一个类中的所测试方法
        5.1.3在【包上右键】,点击绿色三角形,运行包里面所有类的测试方法
    5.2运行结果:
		5.2.1 绿色表示通过
    	5.2.2 红色表示不通过
    	5.2.3 黄色表示【断言】有问题

断言介绍:Assert.assertEquals(猜测值, 真实值)

public class Test01 {
@Test
    public void test01() {
        // 3.在测试方法里面编写我们要测试的代码
        System.out.println("我是测试方法");
        // int a = 10 / 0;
        // 测试自己的类的功能
        Calcuate calc = new Calcuate();
        int sum = calc.sum(1, 3);
        System.out.println("sum = " + sum);
        // 断言: 看我们猜测的值,和真是的是是否一样
        // Assert.assertEquals(猜测值, 真实值);
        Assert.assertEquals(4, sum);
    }
}
4、Junit常用注解
四个注解的作用(以下四个左边都没有三角形,是自动运行的)
    @Before: 在每个测试方法前执行
    @After: 在每个测试方法后执行
    @BeforeClass: 在所有测试方法前执行
    @AfterClass: 在所有测试方法后执行
public class Test02 {
    @BeforeClass
    public static void testBeforeclass22() {//要添加静态statc修饰
        System.out.println("BeforeClass");
    }

    @AfterClass
    public static void testAfterClass22() {//要添加静态statc修饰
        System.out.println("AfterClass");
    }

    @Before
    public void testBefore22() {
        System.out.println("Before");
    }

    @After
    public void testAfter22() {
        System.out.println("After");
    }

    @Test
    public void test01() {
        System.out.println("我是测试方法");
    }

    @Test
    public void test02() {
        System.out.println("我是测试方法");
    }
}

5、junit的使用需要导入两个jar包

​ hamcrest-core-1.3.jar 和 junit-4.12.jar

2、反射

1、Class对象
1、概念:

​ 类名是Class,这个Class类创建的对象,我们称为Class对象。一个类只有一个class对象。常被命名为clazz或者cls

public final class Class<T> {
    // 成员变量
    // 成员方法
}
2、产生过程及作用

(1)过程

​ JDK1.8前:

​ 当.class文件加载到内存中的方法区域时,JVM会创建一个Class对象,Class对象会保存class文件里面的成员变量,成员方法和构造方法等类里面的信息

​ JDK1.8后:

​ 相比于JDK1.8前,没有了方法区,而是变成了元空间,被创建出来的class对象放到了元空间,但不由JVM控制,而是由OS(操作系统)控制。

(2)作用

​ Class对象是反射必须用到的d东西(因为拿到了Class对象,相当于拿到了类的所有的东西)

3、三种获取class对象的方法
1.类名.class
2.对象名.getClass()
3.Class.forName(类全名); 类全名就是包名.类名

注意:以后工作中,用第三种方式,因为它使用类全名,属于字符串,灵活

一个类只有一个class对象

public class Demo04 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1.类名.class
        Class<Employee> cls1 = Employee.class;
        System.out.println(cls1); //重写了toString方法 class com.itheima.bean.Employee//包名.类名

        // 2.对象名.getClass()
        Employee e = new Employee();//之所以下一句的泛型是向上限定,是因为本语句有可能new的是Employee的子类,也就是多态
        Class<? extends Employee> cls2 = e.getClass();
        System.out.println(cls2);

        // 3.Class.forName(类全名);
        Class<?> cls3 = Class.forName("com.itheima.bean.Employee");//点击Employee类--->copy Reference
        System.out.println(cls3);

        //说明以上三种方法得到的class对象是同一个对象(也就是一个类只有一个class对象)
        System.out.println(cls1 == cls2); // true
        System.out.println(cls1 == cls3); // true
    }
}
4、Class类中的方法
获取Class对象信息的方法(2个)
String getName(); 获取【类全名】
String getSimpleName(); 获取【类名】

Object newInstance(); 创建对象
public class Demo05 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> cls = Class.forName("com.itheima.bean.Employee");

        // String getName(); 获取类全名
        String name = cls.getName();
        System.out.println("name = " + name); // com.itheima.bean.Employee
        // String getSimpleName(); 获获取类名
        String simpleName = cls.getSimpleName();
        System.out.println("simpleName = " + simpleName); // Employee

        // Object newInstance(); 创建对象
        Object obj = cls.newInstance(); // Employee e = new Employee();(即该方法实际上是创建Employee这个类的对象)
        System.out.println(obj);
    }
}
2、反射
1、概念:

​ 在程序运行的时候,通过Class对象得到类里面的【构造方法】,【成员方法】,【成员变量】,操作他们.(对类进行解剖)

2、应用场景:

​ IDEA软件的智能提示、“框架”

3、反射的步骤:

​ 1.获取Class对象
​ 2.调用方法操作对应的内容

4、反射得到并操作构造方法
(1)Constructor类

​ 表示类中的构造方法

(2)得到public的Constructor对象

步骤:

​ 1.得到Class对象

​ 2.通过Class对象的方法得到Constructor对象,如下:

getConstructors: 得到所有的public的构造方法
getConstructor: 得到一个的public的构造方法
(3)得到声明的Constructor对象

声明的Constructor对象即指原本类中所有的构造方法

步骤:

​ 1.得到Class对象

​ 2.通过方法得到声明的Constructor

getDeclaredConstructors: 获取所有声明的构造方法
getDeclaredConstructor: 获取一个声明的构造方法

​ PS:有Declared的得到声明的,不管权限,没有Declared的得到public的

(4)Constructor类的方法(对得到的构造方法进行使用):
Object newInstance(...);

​ a.见代码1:Integer.class != int.class

​ b.见代码2:对通过声明的途径得到的私有构造方法,我们在使用之前必须得调用如下方法才能进行使用

暴力反射
setAccessible(true);
public class Demo061 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 1.得到Class对象
        Class<?> cls = Class.forName("com.itheima.bean.Employee");

        // 2.通过Class对象的方法得到Constructor对象
        // getConstructors得到所有的public的构造方法
        /*Constructor<?>[] constructors = cls.getConstructors();
        for (Constructor<?> c : constructors) {
            System.out.println("c = " + c);
        }*/

        // getConstructor得到一个的public的构造方法
        Constructor<?> c1 = cls.getConstructor();
        System.out.println("c1 = " + c1); // public com.itheima.bean.Employee()
        Object obj1 = c1.newInstance();//相当于创建了一个Employee对象
        System.out.println("obj1 = " + obj1);//obj1 = Employee{name='null', age=0, weight=0.0, height=0.0}

        Constructor<?> c2 = cls.getConstructor(String.class, int.class);//基本数据类型与引用数据类型的Class对象  Integer.clas != int.class,不写Integer
        System.out.println("c2 = " + c2); // public com.itheima.bean.Employee(java.lang.String,int)
        Object obj2 = c2.newInstance("凤姐", 18);//相当于创建了一个Employee对象
        System.out.println("obj2 = " + obj2);//obj2 = Employee{name='凤姐', age=18, weight=0.0, height=0.0}
    }
}
public class Demo062 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 1.得到Class对象
        Class<?> cls = Class.forName("com.itheima.bean.Employee");
        // 2.通过方法得到声明的Constructor
        // getDeclaredConstructors: 获取所有声明的构造方法
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        /*for (Constructor<?> c : declaredConstructors) {
            System.out.println("c = " + c);
        }*/

        // getDeclaredConstructor: 获取一个声明的构造方法
        Constructor<?> c1 = cls.getDeclaredConstructor(String.class);
        System.out.println("c1 = " + c1); // private com.itheima.bean.Employee(java.lang.String)

        // 对于私有的方法,我们在使用前需要进行暴力反射
        c1.setAccessible(true); // 设置可以访问为true
        Object obj1 = c1.newInstance("凤姐");
        System.out.println("obj1 = " + obj1);
    }
}
5、反射得到并操作成员方法
(1)Method类

​ 表示类中的普通方法

(2)得到Method对象

​ 1.得到Class对象
​ 2.调用Class对象的方法得到Method对象

getMethods: 得到所有的public方法,包括父类的
getMethod: 得到一个的public方法
getDeclaredMethods: 获取所有的声明的方法
getDeclaredMethod: 获取一个声明的方法
(3)Method类的方法(对得到的成员方法进行使用):
Object invoke(Object obj, Object... args)
Object obj: 调用方法的对象
Object... args: 调用方法时传递给方法的参数
Object返回值: 就是这个方法的返回值
public class Demo07 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 1.得到Class对象
        Class<?> cls = Class.forName("com.itheima.bean.Employee");
        Object obj = cls.newInstance();
        // 2.调用Class对象的方法得到Method对象
        // getMethods: 得到所有的public方法,包括父类的(如Object类)
        // Method[] methods = cls.getMethods();
        // for (Method m : methods) {
        //     System.out.println("m = " + m);
        // }

        // getMethod: 得到一个的public方法
        Method m1 = cls.getMethod("setName", String.class);
        System.out.println("m1 = " + m1);
        Object r1 = m1.invoke(obj, "凤姐");
        System.out.println("返回值1 = " + r1);//该方法没有返回值,所以打印出来是null
        System.out.println(obj);//打印出来是一个对象的信息,说明方法执行了

        // getDeclaredMethods: 获取所有的声明的方法(此时打印出来不再会有父类如Object类的方法)
        // Method[] declaredMethods = cls.getDeclaredMethods();
        // for (Method m : declaredMethods) {
        //     System.out.println("m = " + m);
        // }

        // getDeclaredMethod: 获取一个声明的方法
        Method m2 = cls.getDeclaredMethod("sleep", int.class);
        m2.setAccessible(true);//,方法私有,暴力反射
        Object r2 = m2.invoke(obj, 8);
        System.out.println("返回值2 = " + r2);
    }
}
6、单射得到并操作成员变量
(1)Filed类

​ 表示类中的成员变量

(2)得到Filed对象

​ 1.获取Class对象
​ 2.调用Class对象的方法获取Field对象

getFields: 获取所有public的成员变量
getField: 得到一个public的成员变量
getDeclaredFields: 得到所有声明的成员变量
getDeclaredField: 得到一个声明的成员变量
(3)Filed类的方法(对得到的成员变量进行使用)--------->少用,Method和Structor在反射常用

​ 成员变量用于设置值/获取值

设置值:
    基本数据类型: setXxx(Object obj, Xxx x)  例如: setDouble(Object obj, double d), 													setInt(Object obj, int i)
    引用数据类型: set(Object obj, Object arg)

获取值:
    基本数据类型: getXxx(Object obj) 			例如:getDouble()/getInt()
    引用数据类型: get(Object obj);
public class Demo08 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        // 1.获取Class对象
        Class<?> cls = Class.forName("com.itheima.bean.Employee");
        Object obj = cls.newInstance();

        // 2.调用Class对象的方法获取Field对象
        // getFields: 获取所有public的成员变量
        /*Field[] fields = cls.getFields();
        for (Field f : fields) {
            System.out.println("f = " + f);
        }*/

        // getField: 得到一个public的成员变量
        Field f1 = cls.getField("weight");
        System.out.println("f1 = " + f1);
        f1.setDouble(obj, 66.6);
        System.out.println("obj = " + obj);

        System.out.println(f1.getDouble(obj));

        // getDeclaredFields: 得到所有声明的成员变量
        // Field[] declaredFields = cls.getDeclaredFields();
        // for (Field f : declaredFields) {
        //     System.out.println("f = " + f);
        // }

        // getDeclaredField: 得到一个声明的成员变量
        Field f2 = cls.getDeclaredField("name");
        System.out.println("f2 = " + f2);
        f2.setAccessible(true);
        f2.set(obj, "如花");
        System.out.println("obj = " + obj);

        System.out.println(f2.get(obj));

        // 获取成员变量的类型
        Class<?> type = f2.getType();//返回值是一个class对象
        System.out.println(type.getName());//获取【类全名】
        System.out.println("类型: " + type.getSimpleName());//想要得到类名,则用getSimpleName方法(
    }
}
7、反射的应用(优势体现在哪里?)

​ 根据配置文件中的不同类名和方法名,创建不同的对象并调用方法。

1.定义学生/老师等类
2.创建一个配置文件config.properties
    //因为反射要把类名变成class对象,故写类全名;
    //同时,名字不能出现中文,会出现错误
    2.1配置类名
    2.2配置方法名
3.加载properties的数据到Properties对象中
4.根据类名获取Class对象
5.根据方法名获取方法
6.使用反射执行方法
public class Demo09 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 3.加载properties的数据到Properties对象中
        Properties pp = new Properties();
        pp.load(new FileInputStream("day12demo/config.properties"));
        System.out.println("pp = " + pp); // {classname=com.itheima.demo09Reflect.Student, methodname=study}

        String classname = pp.getProperty("classname"); // com.itheima.demo09Reflect.Student
        String methodname = pp.getProperty("methodname"); // study
        // 4.根据类名获取Class对象
        Class<?> cls = Class.forName(classname);
        Object obj = cls.newInstance();
        // 5.根据方法名获取方法
        Method method = cls.getMethod(methodname);
        // 6.使用反射执行方法
        method.invoke(obj);
    }
}

以上的代码所体现反射的好处:

​ 反射降低耦合性,提高代码的灵活性和扩展性。(应用如:框架)

(本例中无需修改内部代码,只需修改一点点配置文件信息就可以得到不同的方法执行的结果)

3、注解

1、概念:

​ 是JDK1.5的新特性(Annotation)。注解的实质是保存了一些数据。

​ 注解给类增加额外的信息,而且它是给java编译器和JVM虚拟机使用的(给程序使用的)

2、作用:
编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
代码分析:通过代码里标识的注解对代码进行分析【使用反射】
3、自定义注解
(1)格式
自定义注解的格式:
    @interface 注解名 {
        // 注解属性
        数据类型 变量名();
    }

注解的属性类型可以有以下四种:

1.8种基本数据类型都可以
2.String,枚举,注解,Class
3.以上类型的一维数组
4、类中的 String和 Class可以

注意:鉴于注解是为了传输一些轻量级的小数据,所以它所支持的类型没有那么多。故对于注解来说自定义类型不行(如Integer、自定义的student类等等)

(2)使用

​ 使用的时候必须要赋值,且每个属性都要有值,否则会编译报错。

@注解名(属性名=属性值, 属性名=属性值)

​ 特殊情况:

​ (1)在自定义注解的时候,可以为其属性设置默认值。属性被设置了默认值的注解在使用的时候可以不用赋值,不赋值编译也不会报错。

​ (2)

a.当注解中只有一个属性,并且属性名是value的时候:在使用注解时,可以省略属性名value

b.当注解中由多个属性,且其中一个属性名是value,其他属性值都有默认值的时候:在使用注解时,可以省略属性名value

public @interface MyAnno2 {
    // 属性
    String name();
    double price() default 18.8; // 默认值
    String[] authros();

    // WeekDay weekDay();//枚举可以
    // MyAnno1 mya();//注解可以
    // Class cls();//类可以
}

enum WeekDay {
    SUN, MON
}
4、元注解

(1)概念:

​ 修饰注解的注解

(2)@Target元注解

​ 作用:限制注解使用的位置(PS:在未使用该元注解的时候,默认情况是注解在哪里都能使用)

@Target(ElementType.TYPE) // 让注解可以在类或接口上使用
@Target(ElementType.CONSTRUCTOR) // 让注解可以在构造方法上使用
@Target(ElementType.METHOD) // 让注解可以在普通方法上使用
@Target(ElementType.FIELD) // 让注解可以在成员变量上使用
@Target(ElementType.LOCAL_VARIABLE) // 让注解可以在局部变量上使用

(3)@Retention元注解

​ 作用:限制注解能够存活到什么时候(PS:在未使用该元注解的时候,默认注解活到CLASS阶段)

@Retention(RetentionPolicy.RUNTIME)//RUNTIME阶段
@Retention(RetentionPolicy.CLASS)//CLASS阶段
@Retention(RetentionPolicy.SOURCE)//SOURCE阶段
SOURCE阶段                   CLASS阶段    RUNTIME阶段
.java(源代码)   ->  编译  ->  .class  ->  运行
5、注解解析
1、概念:

​ 在程序运行的时候,得到注解里面属性值

2、注解解析相关接口:AnnotatedElement接口

​ AnnotatedElement接口定义了解析注解的方法

T getAnnotation(Class<T> annotationClass) 获取某个对象上的单个注解
Annotation[] getAnnotations() 获取某个对象上的所有注解
boolean isAnnotationPresent(Class annotationClass) 判断是否有这个注解

注意:Class, Constructor, Method, Field这类写都实现了AnnotatedElement接口.

3、如何解析注解
注解在谁头上就用谁来获取
假如注解在构造方法上,使用Constructor来获取
假如注解在成员方法上,使用Method来获取
假如注解在成员变量上,使用Field来获取

定义注解:

// 注解
@Retention(RetentionPolicy.RUNTIME)//必写,否则注解只能活到默认阶段class,运行时就获得不到注解内容
public @interface BookAnno {
    String color();
    double price();
}

Book类

public class Book {
    @BookAnno(color = "黄色的", price = 0.99)
    private String name;

    @MyAnno4
    @BookAnno(color = "绿色的", price = 99)
    // 注解上的数据,在任何地方都可以解析出来(灵活)
    public void sale(String color, double price) {
        // 方法参数上的数据,只能在这个方法里面得到
    }
}
public class Demo13 {
    // 我们点左边绿色的三角形,程序就运行起来的.
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        // 获取方法上的注解
        // 1.获取Class对象
        Class<?> cls = Class.forName("com.itheima.demo14注解解析_练习.Book");
        // 2.通过反射获取Method对象
        Method sale = cls.getMethod("sale");
        // 3.解析注解

        // boolean isAnnotationPresent(Class annotationClass) 判断是否有这个注解
        boolean b = sale.isAnnotationPresent(BookAnno.class);
        System.out.println("b = " + b);
        //if语句:先判断有无注解,再进行获取注解
        if (b) {//判断条件别写b==false
            BookAnno anno = sale.getAnnotation(BookAnno.class);
            System.out.println(anno.color() + ":" + anno.price());
        }

        // Annotation[] getAnnotations() 获取某个对象上的所有注解
        Annotation[] annos = sale.getAnnotations();
        for (Annotation a : annos) {
            System.out.println("a = " + a);
        }
    }

    // 单元测试
    @Test
    public void test02() throws Exception {
        Class<?> cls = Class.forName("com.itheima.demo14注解解析_练习.Book");
        Field name = cls.getDeclaredField("name");
        Annotation[] as = name.getAnnotations();
        for (Annotation a : as) {
            System.out.println("a = " + a);
        }
    }
}

模拟JUnit自带的@Test注解,自动运行带@Test注解的方法

// 1.自定义MyTest注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
// 2.自定义一个类,部分方法配置MyTest注解
public class Person {
    public void getUp() {
        System.out.println("起床啦");
    }

    @MyTest
    public void eat() {
        System.out.println("吃饭啦");
    }

    public void study() {
        System.out.println("学习啦");
    }

    @MyTest
    public void sleep() {
        System.out.println("睡觉啦");
    }
}
public class Demo15 {
    public static void main(String[] args) throws Exception {
        // 3.解析注解:
        // 3.1 得到Class对象
        Person s = new Person();
        Class<?> cls = Class.forName("com.itheima.demo15注解案例_模拟Junit.Person");

        // 3.2 得到所有Method
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            // 3.3 如果Method上有注解就运行这个方法
            if (method.isAnnotationPresent(MyTest.class)) {
                method.invoke(s);
            }
        }
    }
}

类加载器把class文件记载道内存中

4、动态代理

1、现实生活代理
				卖票接口
                卖票的功能
你买火车票  -> 黄牛 ->  12306

你买电脑->电脑的代理商-> 神州工厂

黄牛和1230 6实现 卖票接口

​ 代理模式四要素

调用者:   你
真实对象: 真正调用功能的对象(12306)
代理对象: 在调用者和真实对象之间的对象(黄牛)
抽象对象: 代理对象和真实对象都要实现的接口
2、动态代理:

​ 在程序运行的过程中,动态的创建出代理对象

3、代理模式好处

​ 在不改变真实对象代码的情况下可以对真实对象的功能进行增强,还可以拦截方法(见下面的案例)

4、动态代理API

​ Proxy类: proxy翻译为代理,它的其中一个方法如下:

//创建一个代理对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    
    ClassLoader loader //类加载器
    Class<?>[] interfaces//接口数组,创建出的代理对象就会实现这些接口
    InvocationHandler h//执行处理器(是一个接口),作为方法参数,方法调用的时候,是一个实现类对象或者匿名内部类(重写invoke方法)。当执行代理对象的方法时,就会执行这个对象的invoke方法
    Object//返回值:就是创建出的代理对象

    
总结:    
Object 代理对象 = Proxy.newProxyInstance(类加载器, 接口, 执行处理器);
    
5、过程详解
Proxy.newProxyInstance: 创建出一个代理对象,

代理对象会实现参数(第二个参数)指定的接口(本案例实现的是list接口,如此一来,本例中的代理对象就会和ArryList有一样的功能(方法))。

当代理对象调用方法时,就会调用 执行处理器InvocationHandler的被重写的【invoke方法】,invoke方法被重写时候可以是功能增强,也可以是拦截方法

在这里插入图片描述

案例

/*
案例目标:
    使用动态代理增强ArrayList的所有方法,统计ArrayList每个方法调用花费的时间

ArrayList是真实对象
main方法看作是调用者
代理对象是我们创建出来的daiLi对象
抽象对象是我们创建daiLi对象时候实现了InvocationHandler()接口
*/

public class Demo16 {
    public static void main(String[] args) {
        // 创建真实对象
        ArrayList<String> arrayList = new ArrayList<>();

        // Class对象就能够得到类加载器
        // 创建出一个代理对象,代理对象实现了参数指定的接口
        List daiLi = (List) Proxy.newProxyInstance(Demo16.class.getClassLoader(),
                new Class[]{List.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                         Object proxy: 代理对象,一般不处理
                         Method method: 被调用的方法
                         Object[] args: 调用方法时的参数
                        */

                        // System.out.println("invoke: " + method.getName() + ", 参数: " + Arrays.toString(args));

                        // 调用前记录开始时间
                        long start = System.currentTimeMillis();

                        Object re = null;//避免最后的return re;语句的作用域不够
                        // 拦截方法(不给调用者使用remove方法)
                        if (method.getName().equals("remove")) {
                            System.out.println("老子什么都不干!");
                            return false;
                        } else {
                            // 调用真实对象的方法,代理对象调用什么方法,真实对象也调用什么方法
                            re = method.invoke(arrayList, args);
                        }


                        // 调用后记录时间
                        long end = System.currentTimeMillis();
                        System.out.println(method.getName() + " 消耗时间: " + (end - start));

                        return re;//真是对象返回啥,代理对象也返回啥
                    }
                });

        daiLi.add("aa"); // 当调用代理对象的方法,就会执行到 执行处理器的invoke
        daiLi.add("bb");
        daiLi.add("cc");
        daiLi.add("dd");

        daiLi.remove("bb");
        daiLi.set(0, "凤姐");

        System.out.println("arrayList: " + arrayList);
    }
}
         if (method.getName().equals("remove")) {
                        System.out.println("老子什么都不干!");
                        return false;
                    } else {
                        // 调用真实对象的方法,代理对象调用什么方法,真实对象也调用什么方法
                        re = method.invoke(arrayList, args);
                    }


                    // 调用后记录时间
                    long end = System.currentTimeMillis();
                    System.out.println(method.getName() + " 消耗时间: " + (end - start));

                    return re;//真是对象返回啥,代理对象也返回啥
                }
            });

    daiLi.add("aa"); // 当调用代理对象的方法,就会执行到 执行处理器的invoke
    daiLi.add("bb");
    daiLi.add("cc");
    daiLi.add("dd");

    daiLi.remove("bb");
    daiLi.set(0, "凤姐");

    System.out.println("arrayList: " + arrayList);
}

}


























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值