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

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

单元测试
单元测试概述
单元测试
单元测试就是针对最小的功能单元编写测试代码,Java 程序最小的功能单元是方法,因此,单元测试就是针对 Java 方法的测试,进而检查方法的正确性。
目前测试方法是怎么进行的,存在什么问题
只有一个 main 方法,如果一个方法的测试失败了,其他方法测试会受到影响。
无法得到测试的结果报告,需要程序员自己去观察测试是否成功。
无法实现自动化测试。
JUnit 单元测试框架
JUnit 是使用 Java 语言实现的单元测试框架,它是开源的,Java 开发者都应当学习并使用 JUnit 编写单元测试。
此外,几乎所用的 IDE 工具都集成了 JUnit,这样我们就可以直接在 IDE 中编写并运行 JUint 测试,JUnit 目前最先版本是 5。
Junit 优点
JUnit 可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。
JUnit 可以生成全部方法的测试报告。

总结
JUnit 单元测试是做什么的?
测试类中方法的正确性的。
JUnit 单元测试的优点是什么?
JUnit 可以选择执行哪些测试方法,可以一键执行全部测试方法的测试。
JUnit 可以生成测试报告,如果测试良好则是绿色;如果测试失败,则是红色。
单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
单元测试快速入门
步骤 单元测试快速入门
需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门

分析:

将 JUint 的 jar 包导入到项目中

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

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

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

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

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

选中测试方法,选中 “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("查询全部用户名称成功~~~");
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
测试类

/**

  • @author : gxd
  • @date : 2022/7/22 17:32
  • 测试类
  • 目标:单元测试快速入门
  • 步骤 单元测试快速入门
  • 需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门
  • 分析:
    1. 将 JUint 的 jar 包导入到项目中
  • - IDEA 通常整合好可了 JUint 框架,一般需要要导入。
    
  • - 如果 IDEA 没有整合好,需要自己手工导入如下 2 个 JUnit 的 jar 包到模板
    
    1. 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。
    1. 在测试方法上使用 @Test 注解:标注该方法是一个测试方法。
    1. 在测试方法中完成被测试方法的预期正确性测试。
    1. 选中测试方法,选中 “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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
总结
JUnit 单元测试的实现过程是什么样的?
必须导入 JUnit 框架的 jar 包。
定义的测试方法必须是无参数无返回值,且公开的方法。
测试方法使用 @Test 注解标记。
JUint 测试某个方法,测试全部方法怎么处理?成功的标志是什么?
测试某个方法直接右键该方法启动测试。
测试全部方法,可以选择类或者模块启动。
红色失败,绿色成功。
单元测试常用注解
JUnit 常用注解(JUnit 4.xxxx版本)

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

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
JUnit 常用注解(JUnit 5.xxxx 版本)

开始执行的方法:初始化资源。
执行完毕之后的方法:释放资源。
使用与(JUnit 4.xxxx版本) 一样,只是名字换了。

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

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

Student

/**

  • @author : gxd
  • @date : 2022/7/23 17:31
    */
    public class Student {
    }
    1
    2
    3
    4
    5
    6
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
总结
反射的第一步是什么?
获取 Class 类对象,如此才可以解析类的全部成分
获取 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 +
    '}';
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 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 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());
      }
      }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
使用反射技术获取构造器对象并使用
获取构造器的作用依然是初始化一个对象返回。
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
总结
利用反射技术获取构造器对象的方式
getDeclaredConstructors()
getDeclaredConstructor(Class<?>… parameterTypes)
反射得到的构造器可以做什么?
依然是创建对象的
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 +
    '}';
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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());
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
使用反射技术获取成员变量对象并使用
获取成员变量的作用依然是在某个对象中取值、赋值
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
总结
利用反射技术获取成员变量的方式
获取类中成员变量对象的方法
getDeclaredFields()
getDeclaredField(String name)
反射得到成员变量可以做什么?
依然是某个对象中取值和赋值。
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;
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
总结
利用反射技术获取成员对象的方法
获取类中成员方法对象
getDeclaredMethods()
getDeclaredMethodString name, Class<?>… parameterTypes)
反射得到成员方法可以做什么?
依然是在某个对象中触发该方法执行。
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 list1 = new ArrayList<>();
    ArrayList 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
总结
反射为何可以给约定了泛型的集合存入其他类型的元素?
编译成Class文件进入运行阶段的时候,泛型会自动擦除。
反射是作用在运行时的技术,此时已经不存在泛型了。
反射的作用-通用框架的底层原理
案例 反射做通用框架
需求:给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中去。

分析:

定义一个方法,可以接收任意类的对象。
每次收到一个对象后,需要解析这个对象的全部成员变量名称。
这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
使用反射获取对象的 Class 类对象,然后获取全部成员变量信息。
遍历成员变量信息,然后提取本成员变量在对象中的具体值。
存入成员变量名称和值到文件中去即可。
实体类: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;
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
实体类: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;
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
工具类: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();
      }
      }
      }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
主程序:ReflectTest

/**

  • @author : gxd
  • @date : 2022/7/25 11:14
  • 目标: 反射的作用-通用框架的底层原理
  • 案例 反射做通用框架*
  • 需求:给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中去。
  • 分析:
    1. 定义一个方法,可以接收任意类的对象。
    1. 每次收到一个对象后,需要解析这个对象的全部成员变量名称。
    1. 这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
    1. 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息。
    1. 遍历成员变量信息,然后提取本成员变量在对象中的具体值。
    1. 存入成员变量名称和值到文件中去即可。
      */
      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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
总结
反射的作用?
可以在运行时得到一个类的全部成分然后操作。
也可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)
更重要的用途是适合:做Java高级框架
注解
注解的概述
注解概述、作用
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

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

注解的作用是什么呢?
对 Java 中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理有业务需求来决定。
例如:JUint 框架中,标记了注解 @Test 的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。
总结
注解的作用
对 Java 中类、方法、成员变量做标记,然后进行特殊处理。
例如:JUint 框架中,标记了注解 @Test 的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行
自定义注解
自定义注解—格式
自定义注解就是自己做一个注解来使用。

自定义注解:MyBook

/**

  • @author : gxd
  • @date : 2022/7/25 14:33
    */
    public @interface MyBook {
    String name();
    String[] authors();
    double price();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    主程序: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;
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
特殊属性
value 属性,如果只有一个 value 属性的情况下,使用 value 属性的时候可以省略 value 名称 不写!
但是如果有多个属性,且多个属性没有默认值,那么 value 名称是不能省略的。
总结
自定义注解

元注解
元注解
元注解:就是注解注解的注解。
元注解有两个:
@Target:约束自定义注解只能在哪些地方使用。
@retention:申明注解的生命周期
MyTest

/**

  • @author : gxd
  • @date : 2022/7/25 16:35
    */
    @Target({ElementType.METHOD,ElementType.FIELD})//元注解
    @Retention(RetentionPolicy.RUNTIME)//一直或者,在运行阶段这个注解也不消失
    public @interface MyTest {
    }
    1
    2
    3
    4
    5
    6
    7
    8
    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) {

    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Target 中可使用的值定义在 ElementType 枚举类中,常用值如下

TYPE:类、接口
FIELD:成员变量
METHOD:成员方法
PARAMETER:方法参数
CONSTRUCTOR:构造器
LOCAL_VARIABLE:局部变量
@Retention 中可使用的值定义在 RetentionPolicy 枚举类汇总,常用值如下

SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值。
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
总结
元注解是什么?
注解注解的注解
@Target 约束自定义注解可以标记的范围。
@Rentention 用来约束自定义注解的存活范围。
注解解析
注解的解析
注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。
与注解解析相关的接口
Annotation:注解的顶级接口,注解都是 Annotation 类型的对象

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

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

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

分析:

定义注解 Book,要求如下:
包含属性:String value() 书名
包含属性:double price() 价格,默认值为 100
包含属性:String[] authors() 多位作者
限制注解使用的位置:类和成员方法上
指定注解的有效范围:RUNTIME
定义 BookStore 类,在类和成员方法上使用 Book 注解
定义 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();
}
1
2
3
4
5
6
7
8
9
10
11
12
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
    1. 定义 BookStore 类,在类和成员方法上使用 Book 注解
    1. 定义 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
总结
注解解析的方式

注解的应用场景一:JUnit框架
案例 模拟JUnit框架
需求:

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

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

/**

  • @author : gxd
  • @date : 2022/7/25 16:35
    */
    @Target({ElementType.METHOD})//元注解
    @Retention(RetentionPolicy.RUNTIME)//一直或者,在运行阶段这个注解也不消失
    public @interface MyTest {
    }
    1
    2
    3
    4
    5
    6
    7
    8
    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);
      }
      }
      }
      }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
动态代理
动态代理概述、快速入门
什么是代理?
代理指:某些场景下对象会找一个代理对象,来辅助自己完成一些工作,如:歌星(经纪人),买房的人(房产中介)。
代理主要干什么,他是如何工作的?

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

如何创建代理对象
Java 中代理的代表类是:java.lang.reflect.Proxy。

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

接口:Skill

/**

  • @author : gxd
  • @date : 2022/7/25 23:21
    */
    public interface Skill {
    void jump();//跳舞
    void sing();//唱歌
    }
    1
    2
    3
    4
    5
    6
    7
    8
    实体类: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 + "开始唱歌!");
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
代理类: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;
        }
        });
        }
        }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
主程序: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();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Java 中如何生成代理,并指定代理干什么事

总结
代理是什么?

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

必须存在接口

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

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

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

先走向代理
代理可以为方法额外做一些辅助工作。
开发真正触发对象的方法的执行。
回到代理中,有代理负责返回结果给方法的调用者。
动态代理的应用案例:做性能分析、代理的好处小结
案例 模拟企业业务功能开发,并完成每个功能的性能统计
需求:

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

定义一个 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();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    实现类: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;
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
代理工具类:ProxyUtil

/**

  • @author : gxd
  • @date : 2022/7/26 0:25
  • 代理工具类
    /
    public class ProxyUtil {
    /
    *
    • 通过一个静态方法,为用户业务对象返回一个代理对象
      */
      public static 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;
      }
      });
      }
      }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
主程序: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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
优化的关键步骤
必须有接口,实现类要实现接口(代理通常是基于接口实现的)。

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

动态代理的优点
可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用。
简化了编程工作、提高了开发效率,同时提高了软件系统的可扩展性。
可以为被代理对象的所有方法做代理。
非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/chu_dianxia/article/details/126058856

posted @ 2024-06-25 00:46  自在现实  阅读(15)  评论(0)    收藏  举报