IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> JAVA基础加强篇12——单元测试、反射、注解、动态代理 -> 正文阅读

[开发测试]JAVA基础加强篇12——单元测试、反射、注解、动态代理

单元测试、反射、注解、动态代理 课程安排

在这里插入图片描述

单元测试

单元测试概述

单元测试

  • 单元测试就是针对最小的功能单元编写测试代码,Java 程序最小的功能单元是方法,因此,单元测试就是针对 Java 方法的测试,进而检查方法的正确性。

目前测试方法是怎么进行的,存在什么问题

  • 只有一个 main 方法,如果一个方法的测试失败了,其他方法测试会受到影响。
  • 无法得到测试的结果报告,需要程序员自己去观察测试是否成功。
  • 无法实现自动化测试。

JUnit 单元测试框架

  • JUnit 是使用 Java 语言实现的单元测试框架,它是开源的,Java 开发者都应当学习并使用 JUnit 编写单元测试。
  • 此外,几乎所用的 IDE 工具都集成了 JUnit,这样我们就可以直接在 IDE 中编写并运行 JUint 测试,JUnit 目前最先版本是 5。

Junit 优点

  • JUnit 可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。
  • JUnit 可以生成全部方法的测试报告。

在这里插入图片描述

总结

  1. JUnit 单元测试是做什么的?
    • 测试类中方法的正确性的。
  2. JUnit 单元测试的优点是什么?
    • JUnit 可以选择执行哪些测试方法,可以一键执行全部测试方法的测试。
    • JUnit 可以生成测试报告,如果测试良好则是绿色;如果测试失败,则是红色。
    • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

单元测试快速入门

步骤 单元测试快速入门

需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门

分析:

  1. 将 JUint 的 jar 包导入到项目中

    • IDEA 通常整合好可了 JUint 框架,一般需要要导入。

    • 如果 IDEA 没有整合好,需要自己手工导入如下 2 个 JUnit 的 jar 包到模板

      在这里插入图片描述

  2. 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。

  3. 在测试方法上使用 @Test 注解:标注该方法是一个测试方法。

  4. 在测试方法中完成被测试方法的预期正确性测试。

  5. 选中测试方法,选中 “JUnit 运行”,如果 测试良好则是绿色;如果测试失败,则是红色

    在这里插入图片描述

业务方法

/**
 * @author : gxd
 * @date : 2022/7/22 17:27
 * 业务方法
 */
public class UserService {
    public String loginName(String loginName,String password){
        if ("admin".equals(loginName) && "123456".equals(password)){
            return "登录成功";
        }else {
            return "用户名或者密码有问题";
        }
    }
    public void selectNames(){
        System.out.println(10/0);
        System.out.println("查询全部用户名称成功~~~");
    }
}

测试类

/**
 * @author : gxd
 * @date : 2022/7/22 17:32
 * 测试类
 *  目标:单元测试快速入门
 *
 *  步骤 单元测试快速入门
 *  需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门
 *  分析:
 *  1. 将 JUint 的 jar 包导入到项目中
 *     - IDEA 通常整合好可了 JUint 框架,一般需要要导入。
 *     - 如果 IDEA 没有整合好,需要自己手工导入如下 2 个 JUnit 的 jar 包到模板
 *  2. 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。
 *  3. 在测试方法上使用 @Test 注解:标注该方法是一个测试方法。
 *  4. 在测试方法中完成被测试方法的预期正确性测试。
 *  5. 选中测试方法,选中 “JUnit 运行”,如果 试良好.则是绿色;如果测试失败,则是红色。

 */
public class TestUserService {
    /**
     * 测试方法
     * 注意点:
     *    1、必须是公开的,无参数 无返回值的方法
     *    2、测试方法必须使用 @Test 注解标记
     */
    @Test
    public void testLoginName(){
        UserService userService = new UserService();
        String rs = userService.loginName("admin","123456");

        //进行预期结构的正确性测试:断言。
        /**
         * public static void assertEquals(String message, Object expected, Object actual)
         * 参数一:消息提示
         * 参数二:你调的这个方法的 userService.loginName 的返回结果一样 ,预期的结果
         * 参数三:实际的结果
         */
        Assert.assertEquals("您的登录业务可能出现问题","登录成功",rs);
    }

    @Test
    public void testSelectNames(){
        UserService userService = new UserService();
        userService.selectNames();
    }
}

总结

  1. JUnit 单元测试的实现过程是什么样的?
    • 必须导入 JUnit 框架的 jar 包。
    • 定义的测试方法必须是无参数无返回值,且公开的方法。
    • 测试方法使用 @Test 注解标记。
  2. JUint 测试某个方法,测试全部方法怎么处理?成功的标志是什么?
    • 测试某个方法直接右键该方法启动测试。
    • 测试全部方法,可以选择类或者模块启动。
    • 红色失败,绿色成功。

单元测试常用注解

JUnit 常用注解(JUnit 4.xxxx版本)

在这里插入图片描述

  • 开始执行的方法:初始化资源。
  • 执行完毕之后的方法:释放资源。
/**
 * @author : gxd
 * @date : 2022/7/22 17:32
 * 测试类
 *  目标:单元测试快速入门
 *
 *  步骤 单元测试快速入门
 *  需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门
 *  分析:
 *  1. 将 JUint 的 jar 包导入到项目中
 *     - IDEA 通常整合好可了 JUint 框架,一般需要要导入。
 *     - 如果 IDEA 没有整合好,需要自己手工导入如下 2 个 JUnit 的 jar 包到模板
 *  2. 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。
 *  3. 在测试方法上使用 @Test 注解:标注该方法是一个测试方法。
 *  4. 在测试方法中完成被测试方法的预期正确性测试。
 *  5. 选中测试方法,选中 “JUnit 运行”,如果 试良好.则是绿色;如果测试失败,则是红色。

 */
public class TestUserService {

    //修饰实例方法的
    @Before
    public void before(){
        System.out.println("======before方法执行一次======");
    }
    @After
    public void after(){
        System.out.println("======after方法执行一次======");
    }

    //修饰静态方法
    @BeforeClass
    public static void beforeClass(){
        System.out.println("======beforeClass方法执行一次======");
    }
    @AfterClass
    public static void afterClass(){
        System.out.println("======afterClass方法执行一次======");
    }

    /**
     * 测试方法
     * 注意点:
     *    1、必须是公开的,无参数 无返回值的方法
     *    2、测试方法必须使用 @Test 注解标记
     */
    @Test
    public void testLoginName(){
        UserService userService = new UserService();
        String rs = userService.loginName("admin","123456");

        //进行预期结构的正确性测试:断言。
        /**
         * public static void assertEquals(String message, Object expected, Object actual)
         * 参数一:消息提示
         * 参数二:你调的这个方法的 userService.loginName 的返回结果一样 ,预期的结果
         * 参数三:实际的结果
         */
        Assert.assertEquals("您的登录业务可能出现问题","登录成功",rs);
    }

    @Test
    public void testSelectNames(){
        UserService userService = new UserService();
        userService.selectNames();
    }
}

JUnit 常用注解(JUnit 5.xxxx 版本)

在这里插入图片描述

  • 开始执行的方法:初始化资源。
  • 执行完毕之后的方法:释放资源。

使用与(JUnit 4.xxxx版本) 一样,只是名字换了。

反射

反射概述

反射概述

  • 反射是指对于任何一个 Class 类,在“运行的时候”都可以直接得到这个类全部部分。
  • 在运行时,可以直接得到这个类的构造器对象:Constructor
  • 在运行时,可以直接得到这个类的成员变量对象:Field
  • 在运行时,可以直接得到这个类的成员方法对象:Method
  • 这种运行时动态获取类信息以及动态调用类中成分的能力称为 Java 语言的反射机制。

反射的关键:

  • 反射的第一步都是先得到编译后的 Class 类对象,然后就可以得到 Class 的全部成分。

|在这里插入图片描述

总结

  1. 反射的基本作用、关键?
    • 反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分。
    • 反射的核心思想和关键就是:得到编译以后的 class 文件对象。

反射获取类对象

反射的第一步:获取 Class 类的对象

在这里插入图片描述

在这里插入图片描述

Student

/**
 * @author : gxd
 * @date : 2022/7/23 17:31
 */
public class Student {
}

Test

/**
 * @author : gxd
 * @date : 2022/7/23 17:32
 * 目标:反射的第一步:获取Class对象
 */
public class Test {
    public static void main(String[] args) throws Exception {
        //1、Class 类中的一个静态方法:forName(全限名:包名 + 类名)
        Class c = Class.forName("com.zwzl.d2_reflect_class.Student");
        System.out.println(c);//Student.class

        //2、类名.class
        Class c1 = Student.class;
        System.out.println(c1);

        //3、对象.getClass() 获取对象对应类的Class对象
        Student s = new Student();
        Class c2 = s.getClass();
        System.out.println(c2);
    }
}

总结

  1. 反射的第一步是什么?
    • 获取 Class 类对象,如此才可以解析类的全部成分
  2. 获取 Class 类的对象三种方式
    • 方式一:Class c1 = Class.forName(“全类名”);
    • 方式二:Class c2 = 类名.class;
    • 方式三:Class c3 = 对象.getClass();

反射获取构造器对象

使用反射技术获取构造器对象并使用

在这里插入图片描述

使用反射技术获取构造器对象并使用

  • 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

  • Class 类中用于构造器的方法

    在这里插入图片描述

Student

/**
 * @author : gxd
 * @date : 2022/7/23 17:54
 */
public class Student {
    private String name;
    private int age;

    private Student() {
        System.out.println("无参数构造器执行!");
    }

    public Student(String name, int age) {
        System.out.println("有参数构造器执行!");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

TestStudent1

/**
 * @author : gxd
 * @date : 2022/7/23 17:56
 * 目标:使用反射技术获取构造器对象并使用
 * - 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
 * - Class 类中用于构造器的方法
 */
public class TestStudent1 {
    /**
     * 1、getConstructors:
     *  获取全部的构造器:只能获取public修饰的构造器。
     *  public Constructor<?>[] getConstructors()
     */
    @Test
    public void getConstructors(){
        //a、第一步:获取类对象
        Class c = Student.class;
        //b、提取类中的全部的构造器对象(这里只能拿public修饰的构造器)
        Constructor[] constructors = c.getConstructors();
        //c、遍历构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }

    /**
     * 2、getDeclaredConstructors():
     * 获取全部的构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。
     * ublic Constructor<?>[] getDeclaredConstructors()
     */
    @Test
    public void getDeclaredConstructors(){
        //a、第一步:获取类对象
        Class c = Student.class;
        //b、提取类中的全部的构造器对象
        Constructor[] constructors = c.getDeclaredConstructors();
        //c、遍历构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }

    /**
     * 3、getConstructor(Class… parameterTypes)
     * 获取某个构造器:只能拿public修饰的某个构造器
     * public Constructor<T> getConstructor(Class<?>... parameterTypes)
     */
    @Test
    public void getConstructor() throws Exception {
        //a、第一步:获取类对象
        Class c = Student.class;
        //b、定位单个构造器对象(按照参数定位无参数构造器,只能拿public修饰的某个构造器)
        Constructor constructor = c.getConstructor();
        System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());

        //c、定位某个有参构造器(只能拿public修饰的某个构造器)
        Constructor constructor1 = c.getConstructor(String.class, int.class);
        System.out.println(constructor1.getName() + "===>" + constructor1.getParameterCount());
    }

    /**
     * 4、getDeclaredConstructor
     * 获取某个构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。
     * public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
     */
    @Test
    public void getDeclaredConstructor() throws Exception {
        //a、第一步:获取类对象
        Class c = Student.class;
        //b、定位单个构造器对象(按照参数定位无参数构造器)
        Constructor constructor = c.getDeclaredConstructor();
        System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());

        //c、定位某个有参构造器
        Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor1.getName() + "===>" + constructor1.getParameterCount());
    }
}

使用反射技术获取构造器对象并使用

  • 获取构造器的作用依然是初始化一个对象返回。

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

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/23 17:57
 * 目标:使用反射技术获取构造器对象并使用
 * - 获取构造器的作用依然是初始化一个对象返回。
 * Constructor 类中用于创建对象的方法
 * - public T newInstance(Object ... initargs):根据指定的构造器创建对象
 * - public void setAccessible(boolean flag):设置为 true,表示取消访问检查,进行暴力反射
 */
public class TestStudent2 {
    //1、调用构造器得到一个类的对象返回。
    @Test
    public void getDeclaredConstructor() throws Exception {
        Class c = Student.class;
        Constructor constructor = c.getDeclaredConstructor();
        System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());

        //如果遇到了私有的构造器,可以暴力反射
        constructor.setAccessible(true);//权限被打开

        Student s = (Student) constructor.newInstance();
        System.out.println(s);

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

        Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor1.getName() + "===>" + constructor1.getParameterCount());

        Student s1 = (Student) constructor1.newInstance("张三", 35);
        System.out.println(s1);
    }
}

总结

  1. 利用反射技术获取构造器对象的方式
    • getDeclaredConstructors()
    • getDeclaredConstructor(Class<?>… parameterTypes)
  2. 反射得到的构造器可以做什么?
    • 依然是创建对象的
      • public newInstance(Object… initargs)
    • 如果是非 public 的构造器,需要打开权限(暴力反射),然后再创建对象
      • setAccessible(boolean)
      • 反射可以破坏封装性,私有的也可以执行了。

反射获取成员变量对象

使用反射技术获取成员变量对象并使用

在这里插入图片描述

使用反射技术获取成员变量对象并使用

  • 反射的第一步是先得到类对象,然后从类对象中或缺类的成分对象。

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

    在这里插入图片描述
    blog.csdnimg.cn/18757b8d91e24ab986297a3abdf112c1.png#pic_center)

Student

/**
 * @author : gxd
 * @date : 2022/7/23 23:07
 */
public class Student {
    private String name;
    private int age;
    public static String schoolName;
    public static final String COUNTTPY = "中国";

    public Student() {
        System.out.println("无参数构造器执行!");
    }

    public Student(String name, int age) {
        System.out.println("有参数构造器执行!");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

FieldTest1

/**
 * @author : gxd
 * @date : 2022/7/23 23:07
 * 目标:使用反射技术获取成员变量对象并使用
 * - 反射的第一步是先得到类对象,然后从类对象中或缺类的成分对象。
 *
 * -Class类中用于获取成员变量的方法
 *   - public Field[] getFields():返回所有成员变量对象的数组(只能拿public的)
 *   - public Field[] getDeclaredFields():返回所有成员变量对象的数组,存在就能拿到
 *   - public Field getField(String name):返回单个成员变量对象(只能拿public的)
 *   - public Field getDeclaredField(String name):返回单个成员变量对象,存在就能拿到
 */
public class FieldTest1 {
    /**
     * 1、获取全部的成员变量
     * public Field[] getDeclaredFields()
     * 获取所有的成员变量对应的Field对象,只要申明了就可以得到
     */
    @Test
    public void getDeclaredFields(){
        //a、定位Class类
        Class c = Student.class;
        //b、定位全部成员变量
        Field[] fields = c.getDeclaredFields();
        //c、遍历一下
        for (Field field : fields) {
            System.out.println(field.getName() + "====>" + field.getType());
        }
    }

    /**
     * 2、获取某个成员变量对象,只要申明了就可以得到
     * public Field getDeclaredField(String name)
     * 参数:成员变量名
     */
    @Test
    public void getDeclaredField() throws Exception {
        //a、定位Class对象
        Class c = Student.class;
        //b、根据名称定位某个成员变量
        Field field = c.getDeclaredField("name");
        System.out.println(field.getName() + "===>" + field.getType());
    }

    /**
     * 3、返回所有成员变量对象的数组(只能拿public的)
     * public Field[] getFields()
     */
    @Test
    public void getFields(){
        Class c = Student.class;
        //(这里只能拿public修饰的成员变量)
        Field[] fields = c.getFields();
        for (Field field : fields) {
            System.out.println(field.getName() + "===>" + field.getType());
        }
    }

    /**
     * 4、返回单个成员变量对象(只能拿public的)
     * public Field getField(String name)
     */
    @Test
    public void getField() throws Exception {
        Class c = Student.class;
        //(只能拿public修饰的某个成员变量)
        Field field = c.getField("schoolName");
        System.out.println(field.getName() + "===>" + field.getType());
    }
}

使用反射技术获取成员变量对象并使用

  • 获取成员变量的作用依然是在某个对象中取值、赋值

Field 类中用于取值、赋值的方法

在这里插入图片描述

/**
 * @author : gxd
 * @date : 2022/7/23 23:07
 * 目标:反射获取成员变量:取值和赋值
 *
 * Field的方法:给成员变量赋值和取值
 *  - public void set(Object obj, Object value):给对象注入某个成员变量数据
 *  - public Object get(Object obj):获取对象的成员变量的值
 *  - public void setAccessible(boolean flag):暴力反射,设置为可以直接访问私有类型的属性。
 *  - public Class<?> getType():获取属性的类型,返回Class对象
 *  - public String getName():获取属性的名称
 */
public class FieldTest2 {

    @Test
    public void setField() throws Exception{
        //a、定位Class对象
        Class c = Student.class;
        //b、根据名称定位某个成员变量
        Field field = c.getDeclaredField("name");

        field.setAccessible(true);//暴力打开权限

        //c、赋值
        Student s = new Student();
        field.set(s,"张三");//s.setName("张三");
        System.out.println(s);

        //d、取值
        String name = (String) field.get(s);//s.getName();
        System.out.println(name);
    }
}

总结

  1. 利用反射技术获取成员变量的方式
    • 获取类中成员变量对象的方法
      • getDeclaredFields()
      • getDeclaredField(String name)
  2. 反射得到成员变量可以做什么?
    • 依然是某个对象中取值和赋值。
      • void set(Object obj, Object value)
      • Object get(Object obj)
    • 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值。
      • setAccessible(boolean)

反射获取方法对象

使用反射技术获取方法对象并使用

在这里插入图片描述

使用反射技术获取方法对象并使用

  • 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

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

    在这里插入图片描述

使用发射技术获取方法对象并使用

  • 获取成员方法的作用依然是在某个对象进行执行此方法

Method 类中用于触发执行的方法

在这里插入图片描述

dog

/**
 * @author : gxd
 * @date : 2022/7/25 8:53
 */
public class Dog {
    private String name;

    public Dog() {
    }

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

    public void run(){
        System.out.println("狗跑的贼快~~~");
    }

    private void eat(){
        System.out.println("狗吃骨头");
    }

    private String eat(String name){
        System.out.println("狗吃" + name);
        return "吃的很开心";
    }
    public static void inAddr(){
        System.out.println("在吉山区有一群单身狗!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

MethodTest1

/**
 * @author : gxd
 * @date : 2022/7/25 9:17
 * 目标:使用反射技术获取方法对象并使用
 *
 * 使用反射技术获取方法对象并使用
 * - 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
 * - Class类中用于获取成员方法的方法
 *    - public Method[] getMethods():、返回所有成员方法对象的数组(只能拿public修饰的)
 *    - public Method[] getDeclaredMethods():返回所有成员方法对象的数组,存在就能拿到
 *    - public Method getMethod(String name, Class<?>... parameterTypes):返回的单个成员方法对象(只能拿public修饰的)
 *    - public Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象,存在就能拿到
 *
 * Method的方法执行:
 *  public Object invoke(Object obj, Object... args)
 *    参数一:触发的是哪个对象的方法执行。
 *    参数二:args:调用方法时传递的实际参数
 */
public class MethodTest1 {

    /**
     * 1、返回所有成员方法对象的数组,存在就能拿到
     * public Method[] getDeclaredMethods()
     */
    @Test
    public void getDeclaredMethods(){
        //a、获取类对象
        Class c = Dog.class;
        //b、提取全部方法:包括私有的
        Method[] methods = c.getDeclaredMethods();
        //c、遍历全部方法
        for (Method method : methods) {
            System.out.println(method.getName() + ",返回类型:" + method.getReturnType() + ",个数:" + method.getParameterCount());
        }
    }

    /**
     * 2、返回单个成员方法对象,存在就能拿到
     * public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
     */
    @Test
    public void getDeclaredMethod() throws Exception {
        //a、获取类对象
        Class c = Dog.class;
        //b、提取单个方法对象
        Method method = c.getDeclaredMethod("eat");
        Method method1 = c.getDeclaredMethod("eat",String.class);

        //暴力打开权限了
        method.setAccessible(true);
        method1.setAccessible(true);

        //c、触发方法的执行
        Dog dog = new Dog();
        //注意:方法如果是没有结果回来的,那么返回的是 null。
        Object rs = method.invoke(dog);
        System.out.println(rs);

        Object rs1 = method1.invoke(dog, "骨头");
        System.out.println(rs1);
    }

    /**
     * 3、返回所有成员方法对象的数组(只能拿public修饰的全部方法)
     * public Method[] getMethods()
     */
    @Test
    public void getMethods(){
        Class c = Dog.class;
        //(只能拿public修饰的全部方法)
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + ",返回类型:" + method.getReturnType() + ",个数:" + method.getParameterCount());
        }
    }

    /**
     * 4、返回的单个成员方法对象(只能拿public修饰的单个方法)
     * public Method getMethod(String name, Class<?>... parameterTypes)
     */
    @Test
    public void getMethod() throws Exception {
        Class c = Dog.class;
        //(只能拿public修饰的单个方法)
        Method method = c.getMethod("run");
        System.out.println(method.getName() + ",返回类型:" + method.getReturnType() + ",个数:" + method.getParameterCount());

        Method method1 = c.getMethod("eat",String.class);
        System.out.println(method1.getName() + ",返回类型:" + method1.getReturnType() + ",个数:" + method1.getParameterCount());
    }
}

总结

  1. 利用反射技术获取成员对象的方法
    • 获取类中成员方法对象
      • getDeclaredMethods()
      • getDeclaredMethodString name, Class<?>… parameterTypes)
  2. 反射得到成员方法可以做什么?
    • 依然是在某个对象中触发该方法执行。
      • Object invoke(Object obj, Object… args)
    • 如果某成员方法是非 public 的,需要打开权限(暴力反射),然后再触发执行
      • setAccessible(boolean)

反射的作用-绕过编译阶段为集合添加数据

反射的作用-绕过编译阶段为集合添加数据

  • 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。

    在这里插入图片描述

  • 泛型只是在编译阶段可以约束结合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList 了,泛型相当于被擦除了。

/**
 * @author : gxd
 * @date : 2022/7/25 10:27
 * 目标:反射的作用-绕过编译阶段为集合添加数据
 * - 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。
 * -泛型只是在编译阶段可以约束结合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList 了,泛型相当于被擦除了。
 */
public class ReflectTet {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<String> list2 = new ArrayList<>();
        System.out.println(list1.getClass());
        System.out.println(list2.getClass());
        System.out.println(list1.getClass() == list2.getClass());//ArrayList.class

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

        ArrayList<Integer> list3 = new ArrayList<>();
        list3.add(15);
        list3.add(85);
        //list3.add("张三");

        Class c = list3.getClass();//ArrayList.class  ===> public boolean add(E e)
        //定位c类中的add方法
        Method method = c.getDeclaredMethod("add", Object.class);
        boolean rs = (boolean)method.invoke(list3,"张三");
        System.out.println(rs);
        System.out.println(list3);
        
        //不用反射也可以做到
        ArrayList list4 = list1;
        list4.add("asdfsd");
        System.out.println(list4);
    }
}

总结

  1. 反射为何可以给约定了泛型的集合存入其他类型的元素?
    • 编译成Class文件进入运行阶段的时候,泛型会自动擦除。
    • 反射是作用在运行时的技术,此时已经不存在泛型了。

反射的作用-通用框架的底层原理

案例 反射做通用框架

需求:给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中去。

在这里插入图片描述

分析:

  1. 定义一个方法,可以接收任意类的对象。
  2. 每次收到一个对象后,需要解析这个对象的全部成员变量名称。
  3. 这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
  4. 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息。
  5. 遍历成员变量信息,然后提取本成员变量在对象中的具体值。
  6. 存入成员变量名称和值到文件中去即可。

实体类:Student

/**
 * @author : gxd
 * @date : 2022/7/25 11:09
 */
public class Student {
    private String name;
    private char sex;
    private int age;
    private String className;
    private String hobby;

    public Student() {
    }

    public Student(String name, char sex, int age, String className, String hobby) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.className = className;
        this.hobby = hobby;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

实体类:Teacher

/**
 * @author : gxd
 * @date : 2022/7/25 11:11
 */
public class Teacher {
    private String name;
    private char sex;
    private double salary;

    public Teacher() {
    }

    public Teacher(String name, char sex, double salary) {
        this.name = name;
        this.sex = sex;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

工具类:MybatisUtil

/**
 * @author : gxd
 * @date : 2022/7/25 11:14
 * 通用框架工具类
 */
public class MybatisUtil {
    /**
     * 保存任意类型的对象
     * @param obj
     */
    public static void save(Object obj){
        try (
                PrintStream ps = new PrintStream(new FileOutputStream("junit-reflect-annotation-proxy-app/src/data.txt",true))
                ){
            //1、提取这个对象的全部成员变量:只有反射可以解决
            Class c = obj.getClass();//c.getSimpleName()获取当前类   c.getName获取全限名:包名+类名
            ps.println("=====================" + c.getSimpleName() + "=====================");

            //2、提取它的全部成员变量
            Field[] fields = c.getDeclaredFields();
            //3、获取成员变量的信息
            for (Field field : fields) {
                String name = field.getName();
                //提取本成员变量在 obj 对象中的值(取值)
                field.setAccessible(true);
                String value = field.get(obj) + "";
                ps.println(name + "=" + value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

主程序:ReflectTest

/**
 * @author : gxd
 * @date : 2022/7/25 11:14
 * 目标: 反射的作用-通用框架的底层原理
 *
 * 案例 反射做通用框架*
 * 需求:给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中去。
 * 分析:
 * 1. 定义一个方法,可以接收任意类的对象。
 * 2. 每次收到一个对象后,需要解析这个对象的全部成员变量名称。
 * 3. 这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
 * 4. 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息。
 * 5. 遍历成员变量信息,然后提取本成员变量在对象中的具体值。
 * 6. 存入成员变量名称和值到文件中去即可。
 */
public class ReflectTest {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
        s.setAge(22);
        s.setSex('男');
        s.setClassName("大四");
        s.setHobby("学习");
        MybatisUtil.save(s);

        Teacher t = new Teacher();
        t.setName("老师");
        t.setSex('男');
        t.setSalary(10000);
        MybatisUtil.save(t);
    }
}

总结

  1. 反射的作用?
    • 可以在运行时得到一个类的全部成分然后操作。
    • 也可以破坏封装性。(很突出)
    • 也可以破坏泛型的约束性。(很突出)
    • 更重要的用途是适合:做Java高级框架

注解

注解的概述

注解概述、作用

  • Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

  • Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。

    在这里插入图片描述

注解的作用是什么呢?

  • 对 Java 中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理有业务需求来决定。
  • 例如:JUint 框架中,标记了注解 @Test 的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。

总结

  1. 注解的作用
    • 对 Java 中类、方法、成员变量做标记,然后进行特殊处理。
    • 例如:JUint 框架中,标记了注解 @Test 的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行

自定义注解

自定义注解—格式

  • 自定义注解就是自己做一个注解来使用。

    在这里插入图片描述

自定义注解:MyBook

/**
 * @author : gxd
 * @date : 2022/7/25 14:33
 */
public @interface MyBook {
    String name();
    String[] authors();
    double price();
}

主程序:AnnotationTest1

/**
 * @author : gxd
 * @date : 2022/7/25 15:29
 * 目标:学会自定义注解。掌握其自定义格式和语法。
 */
@MyBook(name = "《精通JavaSE》",authors = {"自我自律","zwzl"},price = 100)
public class AnnotationTest1 {
    @MyBook(name = "《精通JavaSE》",authors = {"自我自律","zwzl"},price = 100)
    private AnnotationTest1(){
    }

    @MyBook(name = "《精通JavaSE1》",authors = {"自我自律","zwzl"},price = 100)
    public static void main(String[] args) {
        @MyBook(name = "《精通JavaSE2》",authors = {"自我自律","zwzl"},price = 100)
        int age = 21;
    }
}

特殊属性

  • value 属性,如果只有一个 value 属性的情况下,使用 value 属性的时候可以省略 value 名称 不写!
  • 但是如果有多个属性,且多个属性没有默认值,那么 value 名称是不能省略的。

总结

  1. 自定义注解

    在这里插入图片描述

元注解

元注解

  • 元注解:就是注解注解的注解。

元注解有两个:

  • @Target:约束自定义注解只能在哪些地方使用。
  • @retention:申明注解的生命周期

MyTest

/**
 * @author : gxd
 * @date : 2022/7/25 16:35
 */
@Target({ElementType.METHOD,ElementType.FIELD})//元注解
@Retention(RetentionPolicy.RUNTIME)//一直或者,在运行阶段这个注解也不消失
public @interface MyTest {
}

AnnotationTest2

/**
 * @author : gxd
 * @date : 2022/7/25 16:36
 * 目标:认识元注解
 * @MyTest //只能注解方法和成员变量,有@Target在@MyTest注解里面控制
 */
public class AnnotationTest2 {
    @MyTest
    private String name;

    @MyTest
    public void test(){

    }

    public static void main(String[] args) {

    }
}

@Target 中可使用的值定义在 ElementType 枚举类中,常用值如下

  • TYPE:类、接口
  • FIELD:成员变量
  • METHOD:成员方法
  • PARAMETER:方法参数
  • CONSTRUCTOR:构造器
  • LOCAL_VARIABLE:局部变量

@Retention 中可使用的值定义在 RetentionPolicy 枚举类汇总,常用值如下

  • SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
  • CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值。
  • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

总结

  1. 元注解是什么?
    • 注解注解的注解
    • @Target 约束自定义注解可以标记的范围。
    • @Rentention 用来约束自定义注解的存活范围。

注解解析

注解的解析

  • 注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。

与注解解析相关的接口

  • Annotation:注解的顶级接口,注解都是 Annotation 类型的对象

  • AnnotatedElement:该接口定义了注解解析相关的解析方法

    在这里插入图片描述

  • 所有的类成分 Class,Method,Filed,Constructor,都实现了 AnnotatedElement 接口他们都拥有解析注解的能力。

解析注解的技巧

  • 注解在哪个成分上,我们就先拿哪个成分对象。
  • 比如注解作用成员方法,则要获得该成员方法对应的 Method 对象,再来拿上面的注解
  • 比如注解作用在类上,则要该类的 Class 对象,再来拿上面的注解
  • 比如注解作用在成员变量上,则要获得该成员变量对应的 Field 对象,再来拿上面的注解

案例 注解解析的案例

需求:注解解析的案例

分析:

  1. 定义注解 Book,要求如下:
    • 包含属性:String value() 书名
    • 包含属性:double price() 价格,默认值为 100
    • 包含属性:String[] authors() 多位作者
    • 限制注解使用的位置:类和成员方法上
    • 指定注解的有效范围:RUNTIME
  2. 定义 BookStore 类,在类和成员方法上使用 Book 注解
  3. 定义 AnnotationTest1 测试类获取 Book 注解上的数据

NewBook:

/**
 * @author : gxd
 * @date : 2022/7/25 22:07
 */

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NewBook {
    String value();
    double price() default 100;
    String[] author();
}

AnnotationTest3 和 BookStore:

/**
 * @author : gxd
 * @date : 2022/7/25 22:10
 * 目标:学会注解解析
 *
 * 注解的解析
 * - 注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。
 * 与注解解析相关的接口
 * - Annotation:注解的顶级接口,注解都是 Annotation 类型的对象
 * - AnnotatedElement:该接口定义了注解解析相关的解析方法
 *     - public Annotation[] getDeclaredAnnotations():获得当前对象上使用的所有注解,返回注解数组。
 *     - public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass):根据注解类型获得对应注解对象
 *     - public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
 * -所有的类成分 Class,Method,Filed,Constructor,都实现了 AnnotatedElement 接口他们都拥有解析注解的能力。
 *
 * 解析注解的技巧
 * - 注解在哪个成分上,我们就先拿哪个成分对象。
 * - 比如注解作用成员方法,则要获得该成员方法对应的 Method 对象,再来拿上面的注解
 * - 比如注解作用在类上,则要该类的 Class 对象,再来拿上面的注解
 * - 比如注解作用在成员变量上,则要获得该成员变量对应的 Field 对象,再来拿上面的注解
 *
 * 案例 注解解析的案例
 * 需求:注解解析的案例
 * 分析:
 * 1. 定义注解 Book,要求如下:
 *    - 包含属性:String value() 书名
 *    - 包含属性:double price() 价格,默认值为 100
 *    - 包含属性:String[] authors() 多位作者
 *    - 限制注解使用的位置:类和成员方法上
 *    - 指定注解的有效范围:RUNTIME
 * 2. 定义 BookStore 类,在类和成员方法上使用 Book 注解
 * 3. 定义 AnnotationTest1 测试类获取 Book 注解上的数据
 */
public class AnnotationTest3 {
    @Test
    public void parseClass(){
        //a、先得到类的对象
        Class c = BookStore.class;
        //b、判断这个类上面是否存在这个注解
        if (c.isAnnotationPresent(NewBook.class)){
            //c、直接获取该注解对象
            NewBook newBook = (NewBook) c.getDeclaredAnnotation(NewBook.class);
            System.out.println(newBook.value());
            System.out.println(newBook.price());
            System.out.println(Arrays.toString(newBook.author()));
        }
    }

    @Test
    public void parseMethod() throws Exception {
        //a、先得到类的对象
        Class c = BookStore.class;
        Method method = c.getDeclaredMethod("test");
        //b、判断这个方法上面是否存在这个注解
        if (method.isAnnotationPresent(NewBook.class)){
            //c、直接获取该注解对象
            NewBook newBook = method.getDeclaredAnnotation(NewBook.class);
            System.out.println(newBook.value());
            System.out.println(newBook.price());
            System.out.println(Arrays.toString(newBook.author()));
        }
    }
}

@NewBook(value = "《法外狂徒张三》",price = 100,author = {"张三","罗老师"})
class BookStore{
    @NewBook(value = "《三少爷的剑》",price = 66,author = {"古龙","熊耀华"})
    public void test(){
    }
}

总结

  1. 注解解析的方式

    在这里插入图片描述

注解的应用场景一:JUnit框架

案例 模拟JUnit框架

需求:

  • 定义若干个方法,只要加了 @MyTest 注解,就可以在启动时被触发执行

分析:

  1. 定义一个自定义注解 @MyTest,只能注解方法,存活范围是一直都在。
  2. 定义若干个方法,只要有 @MyTest 注解的方法就能在启动时被触发执行,没有这个主机的方法不能执行。

MyTest:

/**
 * @author : gxd
 * @date : 2022/7/25 16:35
 */
@Target({ElementType.METHOD})//元注解
@Retention(RetentionPolicy.RUNTIME)//一直或者,在运行阶段这个注解也不消失
public @interface MyTest {
}

AnnotationTest4

/**
 * @author : gxd
 * @date : 2022/7/25 22:57
 */
public class AnnotationTest4 {
    @MyTest
    public void test1(){
        System.out.println("=================test1执行=================");
    }

    public void test2(){
        System.out.println("=================test2执行=================");
    }

    @MyTest
    public void test3(){
        System.out.println("=================test3执行=================");
    }

    /**
     * 启动菜单,有注解的才被调用
     */
    public static void main(String[] args) throws Exception {
        AnnotationTest4 t = new AnnotationTest4();
        //a、获取类对象
        Class c = AnnotationTest4.class;
        //b、提取全部方法
        Method[] methods = c.getDeclaredMethods();
        //c、遍历方法,看是否有 @MyTest 注解,有就跑它
        for (Method method : methods) {
            if (method.isAnnotationPresent(MyTest.class)){
                //跑它
                method.invoke(t);
            }
        }
    }
}

动态代理

动态代理概述、快速入门

什么是代理?

  • 代理指:某些场景下对象会找一个代理对象,来辅助自己完成一些工作,如:歌星(经纪人),买房的人(房产中介)。

代理主要干什么,他是如何工作的?

在这里插入图片描述

代理主要是针对对象的行为额外做一些辅助操作。

如何创建代理对象

  • Java 中代理的代表类是:java.lang.reflect.Proxy。

  • Proxy 提供了一个静态方法,用于为对象产生一个代理对象返回。

    在这里插入图片描述

接口:Skill

/**
 * @author : gxd
 * @date : 2022/7/25 23:21
 */
public interface Skill {
    void jump();//跳舞
    void sing();//唱歌
}

实体类:Star

/**
 * @author : gxd
 * @date : 2022/7/25 23:21
 */
public class Star implements Skill{
    private String name;

    public Star() {
    }

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

    @Override
    public void jump() {
        System.out.println(name + "开始跳舞!");
    }

    @Override
    public void sing() {
        System.out.println(name + "开始唱歌!");
    }
}

代理类:StarAgentProxy

/**
 * @author : gxd
 * @date : 2022/7/25 23:32
 * 代理类
 */
public class StarAgentProxy {
    /**
     * 设计一个方法来返回一个明星对象的代理对象。
     */
    public static Skill getProxy(Star s){
        /**
         *  public static Object newProxyInstance(ClassLoader loader,
         *                                           Class<?>[] interfaces,
         *                                           InvocationHandler h)
         * 参数一:定义代理类的类加载器
         * 参数二:代理类要实现的接口列表
         * 参数三:将方法调用分派到的处理程序。(代理对象的核心处理程序)
         */
        return (Skill) Proxy.newProxyInstance(s.getClass().getClassLoader(),
                s.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("收首付款……");
                        //真正让明星去唱歌和跳舞…
                        //method 正在调用的方法对象 , args 代表这个方法的参数。
                        Object rs = method.invoke(s, args);
                        System.out.println("收尾款,把杨超月接回来……");
                        return rs;
                    }
                });
    }
}

主程序:Test

/**
 * @author : gxd
 * @date : 2022/7/25 23:25
 * 目标:学习开发一个动态代理的对象出来,理解动态代理的执行流程
 */
public class Test {
    public static void main(String[] args) {
        //1、创建一个对象(杨超月),对象的了必须实现接口
        Star star = new Star("杨超月");
        //为杨超月对象,生成一个代理对象(经纪人)
        Skill skill = StarAgentProxy.getProxy(star);
        skill.jump();//走代理的
        skill.sing();
    }
}

Java 中如何生成代理,并指定代理干什么事

在这里插入图片描述

在这里插入图片描述

总结

  1. 代理是什么?

    • 一个对象,用来对被代理对象的行为额外做一些辅助工作。
  2. 在 Java 中实现动态代理的步骤是什么样的?

    • 必须存在接口

    • 被代理对象需要实现接口。

    • 使用 Proxy 类提供的方法,的对象的代表对象。

      在这里插入图片描述

  3. 通过代理对象调用方法,执行流程是什么样的?

    • 先走向代理
    • 代理可以为方法额外做一些辅助工作。
    • 开发真正触发对象的方法的执行。
    • 回到代理中,有代理负责返回结果给方法的调用者。

动态代理的应用案例:做性能分析、代理的好处小结

案例 模拟企业业务功能开发,并完成每个功能的性能统计

需求:

  • 模拟企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。

分析:

  • 定义一个 UserService 表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。
  • 定义一个实现类 UserServiceImpl 实现 UserService ,并完成相关功能,且统计每个功能的耗时。
  • 定义测试列,创建实现类对象,调用方法。

本案例存在哪些问题?

  • 业务对象的每个方法都要进行性能统计,存在大量重复的代码。
  • 解决方案,使用动态代理

接口:UserService

/**
 * @author : gxd
 * @date : 2022/7/26 0:13
 */
public interface UserService {
    String login(String loginName,String passWord);
    void deleteUsers();
    String selectUsers();
}

实现类:UserServiceImpl

/**
 * @author : gxd
 * @date : 2022/7/26 0:14
 */
public class UserServiceImpl implements UserService{
    @Override
    public String login(String loginName, String passWord) {
        String rs = "登录名和密码错误!";
        if ("admin".equals(loginName) && "123456".equals(passWord)){
            rs = "登录成功!";
        }
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rs;
    }

    @Override
    public void deleteUsers() {
        try {
            System.out.println("您正在删除用户数据中……");
            Thread.sleep(2500);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String selectUsers() {
        String rs = "查询了10000个用户数据!";
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rs;
    }
}

代理工具类:ProxyUtil

/**
 * @author : gxd
 * @date : 2022/7/26 0:25
 * 代理工具类
 */
public class ProxyUtil {
    /**
     * 通过一个静态方法,为用户业务对象返回一个代理对象
     */
    public static <T> T getProxy(T userService){
        return (T) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long startTime = System.currentTimeMillis();
                        Object rs = method.invoke(userService, args);
                        long endTime = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");
                        return rs;
                    }
                });
    }
}

主程序:Test

/**
 * @author : gxd
 * @date : 2022/7/26 0:11
 * 目标:掌握使用动态代理解决问题,理解使用动态代理的优势。
 *
 * 案例 模拟企业业务功能开发,并完成每个功能的性能统计
 *
 * 需求:
 * - 模拟企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。
 *
 * 分析:
 * - 定义一个 UserService 表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。
 * - 定义一个实现类 UserServiceImpl 实现 UserService ,并完成相关功能,且统计每个功能的耗时。
 * - 定义测试列,创建实现类对象,调用方法。
 */
public class Test {
    public static void main(String[] args) {
        UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
        System.out.println(userService.login("admin","123456"));
        System.out.println(userService.selectUsers());
        userService.deleteUsers();
    }
}

优化的关键步骤

  1. 必须有接口,实现类要实现接口(代理通常是基于接口实现的)。

  2. 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

    在这里插入图片描述

动态代理的优点

  • 可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用。
  • 简化了编程工作、提高了开发效率,同时提高了软件系统的可扩展性。
  • 可以为被代理对象的所有方法做代理。
  • 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:12:24  更:2022-08-06 11:12:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 10:56:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码