今日内容

  • JUnit单元测试
  • 反射
  • 注解
  • 动态代理
  • JDK8新特性

学习目标

  • 能够使用Junit进行单元测试
  • 能够通过反射技术获取Class字节码对象
  • 能够通过反射技术获取构造方法对象,并创建对象。
  • 能够通过反射获取成员方法对象,并且调用方法。
  • 能够通过反射获取属性对象,并且能够给对象的属性赋值和取值。
  • 能够说出注解的作用
  • 能够自定义注解和使用注解
  • 能够说出常用的元注解及其作用
  • 能够解析注解并获取注解中的数据
  • 能够完成注解的MyTest案例
  • 能够说出动态代理模式的作用
  • 能够使用Proxy的方法生成代理对象
  • 能够使用四种方法的引用
  • 能够使用Base64对基本数据、URL和MIME类型进行编解码

第一章 Junit单元测试

知识点—Junit单元测试

目标

  • 掌握Junit的使用

路径

  • Junit的概念
  • Junit的使用步骤
  • 执行测试方法

讲解

Junit的概念

  • 概述 : Junit是Java语言编写的第三方单元测试框架(工具类)
  • 作用 : 用来做“单元测试”——针对某个普通方法,可以像main()方法一样独立运行,它专门用于测试某个方法。

Junit的使用步骤

  • 1.在模块下创建lib文件夹,把Junit的jar包复制到lib文件夹中

  • 2.选中Junit的jar包,右键选中 add as Library,把JUnit4的jar包添加到classPath中

  • 3.在测试方法上面写上@Test注解

  • 4.执行测试方法 ```java public class Person {

    @Test public void test1(){

    1. System.out.println("Person test1 方法执行了....");

    }

    @Test public void test2(){

    1. System.out.println("Person test2 方法执行了....");

    }

}

  1. <a name="43db8fcf"></a>
  2. #### 执行测试方法
  3. -
  4. 1.选中方法名--->右键--->选中执行 只执行选中的测试方法
  5. -
  6. 2.选中类名----->右键--->选中执行 执行该类中所有的测试方法
  7. -
  8. 3.选中模块---- ->右键--->选中all tests 执行 执行该模块中所有的测试方法
  9. -
  10. 如何查看测试结果
  11. - 绿色:表示测试通过
  12. - 红色:表示测试失败,有问题
  13. <a name="5db9fd7c"></a>
  14. ### 小结
  15. <a name="9ab62e95"></a>
  16. ## 知识点--Junit单元测试的注意实现
  17. <a name="73e82552-1"></a>
  18. ### 目标
  19. - 测试方法注意事项:
  20. <a name="4f35e80d-1"></a>
  21. ### 路径
  22. - 测试方法注意事项:
  23. <a name="ab2acfc6-1"></a>
  24. ### 讲解
  25. - 1.测试方法的权限修饰符一定是public
  26. - 2.测试方法的返回值类型一定是void
  27. - 3.测试方法一定没有参数
  28. - 4.测试方法 的声明之上一定要使用@Test注解
  29. <a name="5db9fd7c-1"></a>
  30. ### 小结
  31. - 测试方法一定是一个公共的无参数无返回值的方法
  32. <a name="d4fbd8f4"></a>
  33. ## 知识点--Junit其他注解
  34. <a name="73e82552-2"></a>
  35. ### 目标
  36. - Junit其他注解的使用
  37. <a name="4f35e80d-2"></a>
  38. ### 路径
  39. - Junit其他注解
  40. <a name="ab2acfc6-2"></a>
  41. ### 讲解
  42. - @Before:用来修饰方法,该方法会在每一个测试方法执行之前执行一次。
  43. - @After:用来修饰方法,该方法会在每一个测试方法执行之后执行一次。
  44. - @BeforeClass:用来静态修饰方法,该方法会在所有测试方法之前执行一次,而且只执行一次。
  45. - @AfterClass:用来静态修饰方法,该方法会在所有测试方法之后执行一次,而且只执行一次。
  46. ```java
  47. public class Student {
  48. @BeforeClass
  49. public static void beforeClass1(){
  50. System.out.println("Student beforeClass1静态方法执行了...");
  51. }
  52. @BeforeClass
  53. public static void beforeClass2(){
  54. System.out.println("Student beforeClass2静态方法执行了...");
  55. }
  56. @Before
  57. public void b1(){
  58. System.out.println("Student b1方法执行了...");
  59. }
  60. @Before
  61. public void b2(){
  62. System.out.println("Student b2方法执行了...");
  63. }
  64. @Before
  65. public void b3(){
  66. System.out.println("Student b3方法执行了...");
  67. }
  68. @Test
  69. public void test1(){
  70. System.out.println("Student test1 方法执行了....");
  71. }
  72. @Test
  73. public void test2(){
  74. System.out.println("Student test2 方法执行了....");
  75. }
  76. @After
  77. public void a1(){
  78. System.out.println("Student a1方法执行了...");
  79. }
  80. @After
  81. public void a2(){
  82. System.out.println("Student a2方法执行了...");
  83. }
  84. @After
  85. public void a3(){
  86. System.out.println("Student a3方法执行了...");
  87. }
  88. @AfterClass
  89. public static void afterClass1(){
  90. System.out.println("Student afterClass1方法执行了...");
  91. }
  92. @AfterClass
  93. public static void afterClass2(){
  94. System.out.println("Student afterClass2方法执行了...");
  95. }
  96. }

小结

知识点—Junit断言

目标

  • Junit断言

路径

  • Junit断言

讲解

  • 断言:预先判断某个条件是否成立,如果条件不成立,则直接报错。 使用Assert类中的assertEquals()方法
  • 案例:
  1. public class Demo02 {
  2. @Test
  3. public void addTest(){
  4. //测试
  5. int add = add(3, 6);
  6. //断言判断结果
  7. //第一个参数表示期望值
  8. //第二个参数表示实际值
  9. //如果结果正确的就测试通过,如果结果错误的,就会报错
  10. Assert.assertEquals(9,add);
  11. }
  12. //加法
  13. //这个代码的语法没问题,也没有异常。他是逻辑错误,系统不知道你要算的是加法
  14. public int add(int a, int b){
  15. int sum = a * b;
  16. return sum;
  17. }
  18. }

小结

第二章 反射

知识点—类加载器

目标

  • 理解类在什么时候加载,以及如何获取类加载器

路径

  • 类的加载
  • 类的加载时机
  • 类加载器

讲解

类的加载

  • 当我们的程序在运行后,第一次使用某个类的时候,会将此类的class文件读取到内存,并将此类的所有信息存储到一个Class对象中

day15【JUnit单元测试、反射、注解、动态代理、JDK8新特性】 - 图1

类的加载时机

  1. 创建类的实例。

  2. 类的静态变量,或者为静态变量赋值。

  3. 类的静态方法。

  4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。

  5. 初始化某个类的子类。

  6. 直接使用java.exe命令来运行某个主类。
    以上六种情况的任何一种,都可以导致JVM将一个类加载到方法区。

  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. // 类的加载时机
  4. // 1. 创建类的实例。
  5. // Student stu = new Student();
  6. // 2. 类的静态变量,或者为静态变量赋值。
  7. // Person.country = "中国";
  8. // 3. 类的静态方法。
  9. // Person.method();
  10. // 4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。
  11. // Class<?> c = Class.forName("com.itheima.demo1_类的加载.Student");
  12. // 5. 初始化某个类的子类。
  13. // Zi zi = new Zi();
  14. // 6. 直接使用java.exe命令来运行某个主类。
  15. }
  16. }

类加载器

  1. **类加载器:是负责将磁盘上的某个class文件读取到内存并生成Class的对象。**
  • Java中有三种类加载器,它们分别用于加载不同种类的class:

    • 启动类加载器(Bootstrap ClassLoader):用于加载系统类库\bin目录下的class,例如:rt.jar。
    • 扩展类加载器(Extension ClassLoader):用于加载扩展类库\lib\ext目录下的class。
    • 应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器。
  1. public class Test{
  2. public static void main(String[] args){
  3. // 获取类加载器:
  4. // 获取Student类的类加载器
  5. System.out.println(Student.class.getClassLoader());// AppClassLoader
  6. // 获取String类的类加载器
  7. System.out.println(String.class.getClassLoader());// null
  8. // API中说明:一些实现可能使用null来表示引导类加载器。 如果此类由引导类加载器加载,则此方法将在此类实现中返回null
  9. }
  10. }

小结

知识点—反射的概述

目标

  • 理解反射的概念

路径

  • 反射的引入
  • 反射的概念
  • 使用反射操作类成员的前提
  • 射在实际开发中的应用

讲解

反射的引入

  • 问题:IDEA中的对象是怎么知道类有哪些属性,哪些方法的呢?
  1. 通过反射技术对象类进行了解剖得到了类的所有成员。

反射的概念

  1. 反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员(成员变量,成员方法,构造方法)

使用反射操作类成员的前提

  1. 要获得该类字节码文件对象,就是Class对象

反射在实际开发中的应用

  1. * 开发IDE(集成开发环境),比如IDEA,Eclipse
  2. * 各种框架的设计和学习 比如SpringHibernateStructMybaits....

小结

  • 通过反射技术去获取一个类的成员变量,成员方法,构造方法…,并可以访问

知识点—Class对象的获取方式

目标

  • 能够获取一个类的Class对象

路径

  • 通过类名.class获得
  • 通过对象名.getClass()方法获得
  • 通过Class类的静态方法获得: static Class forName(“类全名”)

讲解

  1. * 方式1: 通过类名.class获得
  2. * 方式2:通过对象名.getClass()方法获得
  3. * 方式3:通过Class类的静态方法获得: static Class forName("类全名")
  4. * 每一个类的Class对象都只有一个。
  • 示例代码
  1. package com.itheima.demo2_Class对象的获取;
  2. /**
  3. * @Author:pengzhilin
  4. * @Date: 2020/5/14 9:35
  5. */
  6. public class Student {
  7. private String name;
  8. public void method1(){
  9. }
  10. }
  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. /*
  4. Class对象的获取:
  5. 通过类名.class获得
  6. 通过对象名.getClass()方法获得
  7. 通过Class类的静态方法获得: static Class forName("类全名")
  8. */
  9. // 1.方式一:通过类名.class获得
  10. Class<Student> c1 = Student.class;
  11. System.out.println(c1);
  12. // 2.方式二:通过对象名.getClass()方法获得
  13. Student stu = new Student();
  14. Class<? extends Student> c2 = stu.getClass();
  15. System.out.println(c2);
  16. // 3.方式三:通过Class类的静态方法获得: static Class forName("类全名")
  17. Class<?> c3 = Class.forName("com.itheima.demo2_Class对象的获取.Student");
  18. System.out.println(c3);
  19. // 问题:一个类只有一个字节码对象(Class对象)
  20. System.out.println(c1 == c2);// true
  21. System.out.println(c1 == c3);// true
  22. }
  23. }

小结

知识点—Class类常用方法

目标

  • Class类的常用方法

路径

  • Class类的常用方法

讲解

  1. String getSimpleName(); 获得类名字符串:类名
  2. String getName(); 获得类全名:包名+类名
  3. T newInstance() ; 创建Class对象关联类的对象
  • 示例代码
  1. public class ReflectDemo02 {
  2. public static void main(String[] args) throws Exception {
  3. // 获得Class对象
  4. Class c = Student.class;
  5. // 获得类名字符串:类名
  6. System.out.println(c.getSimpleName());
  7. // 获得类全名:包名+类名
  8. System.out.println(c.getName());
  9. // 创建对象
  10. Student stu = (Student) c.newInstance();
  11. System.out.println(stu);
  12. }
  13. }

小结

知识点—反射之操作构造方法

目标

  • 通过反射获取类的构造方法,并执行构造方法

路径

  • Constructor类概述
  • 通过反射获取类的构造方法
  • 通过反射执行构造方法

讲解

Constructor类概述

  1. 反射之操作构造方法的目的
  2. * 获得Constructor对象来创建类的对象。
  3. Constructor类概述
  4. * 类中的每一个构造方法都是一个Constructor类的对象

通过反射获取类的构造方法

  1. Class类中与Constructor相关的方法
  2. 1. Constructor getConstructor(Class... parameterTypes)
  3. * 根据参数类型获得对应的Constructor对象。
  4. * 只能获得public修饰的构造方法
  5. 2. Constructor getDeclaredConstructor(Class... parameterTypes)
  6. * 根据参数类型获得对应的Constructor对象
  7. * 可以是publicprotected、(默认)、private修饰符的构造方法。
  8. 3. Constructor[] getConstructors()
  9. 获得类中的所有构造方法对象,只能获得public
  10. 4. Constructor[] getDeclaredConstructors()
  11. 获得类中的所有构造方法对象
  12. 可以是publicprotected、(默认)、private修饰符的构造方法。

通过反射执行构造方法

  1. Constructor对象常用方法
  2. 1. T newInstance(Object... initargs)
  3. 根据指定的参数创建对象
  4. 2. void setAccessible(true)
  5. 设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消

示例代码

  1. package com.itheima.demo4_反射之构造方法;
  2. /**
  3. * @Author:pengzhilin
  4. * @Date: 2020/5/14 10:13
  5. */
  6. public class Student {
  7. // 属性
  8. public String name;// 姓名
  9. public String sex;// 性别
  10. public int age;// 年龄
  11. // 构造方法
  12. public Student() {
  13. }
  14. public Student(String name, String sex, int age) {
  15. this.name = name;
  16. this.sex = sex;
  17. this.age = age;
  18. }
  19. private Student(String name, int age) {
  20. this.name = name;
  21. this.age = age;
  22. }
  23. // 成员方法
  24. @Override
  25. public String toString() {
  26. return "Student{" +
  27. "name='" + name + '\'' +
  28. ", sex='" + sex + '\'' +
  29. ", age=" + age +
  30. '}';
  31. }
  32. }
  1. public class Test1 {
  2. public static void main(String[] args) throws Exception{
  3. /*
  4. - 通过反射获取类的构造方法,并执行构造方法创建该类的对象
  5. - Constructor类概述
  6. 概述:类中的每一个构造方法都是一个Constructor类的对象
  7. 通过反射获取类的构造方法,其实就是获取该构造方法对于的Constructor对象
  8. - 通过反射获取类的构造方法: 使用Class类中的方法
  9. 我们每一个类都会有一个对于的Class对象,所以该类中的构造方法就在我们的Class对象中,
  10. 所以可以使用Class对象获取构造方法
  11. Class类中与Constructor相关的方法
  12. 1. Constructor getConstructor(Class... parameterTypes) 获取单个public修饰的构造方法
  13. * 根据参数类型获得对应的Constructor对象。
  14. * 只能获得public修饰的构造方法
  15. 2. Constructor getDeclaredConstructor(Class... parameterTypes) 获取单个构造方法
  16. * 根据参数类型获得对应的Constructor对象
  17. * 可以是public、protected、(默认)、private修饰符的构造方法。
  18. 3. Constructor[] getConstructors() 获取所有public修饰的构造方法
  19. 获得类中的所有构造方法对象,只能获得public的
  20. 4. Constructor[] getDeclaredConstructors() 获取所有构造方法
  21. 获得类中的所有构造方法对象
  22. 可以是public、protected、(默认)、private修饰符的构造方法。
  23. 记忆方法:
  24. 1. 加了s的就是获取多个,不加s的就是获取单个
  25. 2. 加了Declared的就是获取任意修饰符修饰的构造方法,不加就只能获取public修饰的构造方法
  26. 小结:
  27. Constructor getDeclaredConstructor(Class... parameterTypes) 获取单个构造方法
  28. Constructor[] getDeclaredConstructors() 获取所有构造方法
  29. - 通过反射执行构造方法:使用Constructor对象中的方法,来执行该对象表示的构造方法
  30. Constructor对象常用方法
  31. 1. T newInstance(Object... initargs)
  32. 根据指定的参数创建对象
  33. 2. void setAccessible(true)
  34. 设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消
  35. */
  36. // 0.获取Student类的Class对象
  37. Class<?> c = Class.forName("com.itheima.demo4_反射之构造方法.Student");
  38. // 1.获取单个public修饰的构造方法
  39. // Constructor getConstructor(Class... parameterTypes) 获取单个public修饰的构造方法
  40. // 参数:传入你要获取的构造方法的参数类型的Class对象
  41. // 获取Student类的空参构造方法
  42. Constructor<?> cons1 = c.getConstructor();
  43. System.out.println(cons1);
  44. // 获取Student类的带有三个参数的构造方法,并且参数的类型顺序为:String,String,int
  45. Constructor<?> cons2 = c.getConstructor(String.class,String.class, int.class);
  46. // public Student(String name,String sex,int.class);
  47. // public Student(String name,int.class,String sex);
  48. System.out.println(cons2);
  49. // 2.获取单个非public修饰的构造方法
  50. // Constructor getDeclaredConstructor(Class... parameterTypes) 获取单个构造方法
  51. // 参数:传入你要获取的构造方法的参数类型的Class对象
  52. // 获取Student类的带有2个参数的构造方法,并且参数的类型顺序为:String,int
  53. Constructor<?> cons3 = c.getDeclaredConstructor(String.class, int.class);
  54. System.out.println(cons3);
  55. System.out.println("============================================");
  56. // 3.获取多个public修饰的方法
  57. // Constructor[] getConstructors() 获取所有public修饰的构造方法
  58. Constructor<?>[] conArr1 = c.getConstructors();
  59. for (Constructor<?> con : conArr1) {
  60. System.out.println(con);
  61. }
  62. System.out.println("============================================");
  63. // 4.获取所有修饰的方法
  64. // Constructor[] getDeclaredConstructors() 获取所有构造方法
  65. Constructor<?>[] conArr2 = c.getDeclaredConstructors();
  66. for (Constructor<?> con : conArr2) {
  67. System.out.println(con);
  68. }
  69. }
  70. }
  71. public class Test2 {
  72. public static void main(String[] args) throws Exception{
  73. /*
  74. - 获取类的构造方法:
  75. Constructor getDeclaredConstructor(Class... parameterTypes) 获取单个构造方法
  76. Constructor[] getDeclaredConstructors() 获取所有构造方法
  77. - 通过反射执行构造方法:使用Constructor对象中的方法,来执行该对象表示的构造方法
  78. Constructor对象常用方法
  79. 1. T newInstance(Object... initargs)
  80. 根据指定的参数创建对象
  81. 参数: 传入执行该构造方法需要的实际参数
  82. 2. void setAccessible(boolean b)
  83. 设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消
  84. */
  85. // 获取Student类的Class对象
  86. Class<?> c = Class.forName("com.itheima.demo4_反射之构造方法.Student");
  87. // 1.获取public修饰的构造方法对象,并执行该对象表示的构造方法来创建对象
  88. // 1.1 获取public修饰的构造方法对象 public Student(String name, String sex, int age)
  89. Constructor<?> cons1 = c.getDeclaredConstructor(String.class, String.class, int.class);
  90. // 1.2 执行该对象表示的构造方法来创建对象
  91. Object obj = cons1.newInstance("张三", "女", 18);// 真正返回的是Student对象
  92. System.out.println(obj);// Student{name='张三', sex='女', age=18}
  93. System.out.println("==========================================");
  94. // 2.获取private修饰的构造方法对象,并执行该对象表示的构造方法来创建对象
  95. // 2.1 获取private修饰的构造方法对象
  96. Constructor<?> cons2 = c.getDeclaredConstructor(String.class, int.class);
  97. // 2.2 执行该对象表示的构造方法来创建对象
  98. // 设置"暴力反射"
  99. cons2.setAccessible(true);
  100. Object obj2 = cons2.newInstance("李四", 19);
  101. System.out.println(obj2);
  102. }
  103. }

小结

知识点—反射之操作成员方法

目标

  • 通过反射获取类的成员方法,并执行成员方法

路径

  • Method类概述
  • 通过反射获取类的成员方法
  • 通过反射执行成员方法

讲解

Method类概述

  1. 反射之操作成员方法的目的
  2. * 操作Method对象来调用成员方法
  3. Method类概述
  4. * 每一个成员方法都是一个Method类的对象。

通过反射获取类的成员方法

  1. * Method getMethod(String name,Class...args);
  2. * 根据方法名和参数类型获得对应的成员方法对象,只能获得public
  3. * Method getDeclaredMethod(String name,Class...args); 掌握
  4. * 根据方法名和参数类型获得对应的成员方法对象,包括publicprotected、(默认)、private
  5. * Method[] getMethods();
  6. * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
  7. * Method[] getDeclaredMethods(); 掌握
  8. * 获得类中的所有成员方法对象,返回数组,只获得本类的,包括publicprotected、(默认)、private

通过反射执行成员方法

  1. Method对象常用方法
  2. * Object invoke(Object obj, Object... args)
  3. * 调用指定对象obj的该方法
  4. * args:调用方法时传递的参数
  5. * void setAccessible(true)
  6. 设置"暴力访问"——是否取消权限检查,true取消权限检查,false表示不取消

示例代码

  1. ackage com.itheima.demo5_反射之操作成员方法;
  2. /**
  3. * @Author:pengzhilin
  4. * @Date: 2020/5/14 10:13
  5. */
  6. public class Student {
  7. public void show1(){
  8. System.out.println("public 修饰的show1方法,无参数...");
  9. }
  10. public void show1(String str,int num){
  11. System.out.println("public 修饰的show1方法,2个参数...");
  12. System.out.println("str:"+str+",num:"+num);
  13. }
  14. public void show2(){
  15. System.out.println("public 修饰的show2方法...");
  16. }
  17. private void show3(){
  18. System.out.println("private 修饰的show3方法...");
  19. }
  20. }
  1. package com.itheima.demo5_反射之操作成员方法;
  2. import java.lang.reflect.Method;
  3. /**
  4. * @Author:pengzhilin
  5. * @Date: 2020/5/14 11:03
  6. */
  7. public class Test1 {
  8. public static void main(String[] args) throws Exception {
  9. /*
  10. 反射之操作成员方法:
  11. - 通过反射获取类的成员方法,并通过反射技术执行成员方法
  12. - Method类概述
  13. 每一个成员方法都是一个Method类的对象。
  14. - 通过反射获取类的成员方法
  15. Class类中与Method相关的方法
  16. * Method getMethod(String name,Class...args); 获取单个public修饰的成员方法
  17. * 根据方法名和参数类型获得对应的构造方法对象,只能获得public的
  18. * Method getDeclaredMethod(String name,Class...args); 获取任意修饰符修饰的单个成员方法
  19. * 根据方法名和参数类型获得对应的构造方法对象,包括public、protected、(默认)、private的
  20. * Method[] getMethods(); 获取所有public修饰的成员方法
  21. * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
  22. * Method[] getDeclaredMethods(); 获取所有成员方法
  23. * 获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、private的
  24. 记忆:
  25. Method getDeclaredMethod(String name,Class...args); 获取任意修饰符修饰的单个成员方法\
  26. Method[] getDeclaredMethods(); 获取所有成员方法
  27. - 通过反射执行成员方法
  28. */
  29. // 1.获取Student类的Class对象
  30. Class<?> c = Class.forName("com.itheima.demo5_反射之操作成员方法.Student");
  31. // 2.获取单个成员方法
  32. // 2.1 获取单个public修饰的方法
  33. // Method getMethod(String name,Class...args);
  34. // 第一个参数: 方法名
  35. // 第二个参数: 该方法的参数类型的Class对象,如果没有参数就不传入
  36. Method show1M1 = c.getMethod("show1");// 第一个show1方法
  37. System.out.println(show1M1);
  38. Method show1M2 = c.getMethod("show1", String.class, int.class);
  39. System.out.println(show1M2);
  40. // 2.2 获取单个private修饰的成员方法
  41. // Method getDeclaredMethod(String name,Class...args);
  42. // 第一个参数: 方法名
  43. // 第二个参数: 该方法的参数类型的Class对象,如果没有参数就不传入
  44. Method show3M = c.getDeclaredMethod("show3");
  45. System.out.println(show3M);
  46. System.out.println("=======================");
  47. // 3.获取多个public修饰的成员方法
  48. // 3.1 获取所有public修饰的成员方法
  49. // Method[] getMethods();
  50. Method[] mArr1 = c.getMethods();
  51. for (Method method : mArr1) {
  52. System.out.println(method);
  53. }
  54. System.out.println("=======================");
  55. // 3.2 获取所有的成员方法
  56. // Method[] getDeclaredMethods();
  57. Method[] mArr2 = c.getDeclaredMethods();
  58. for (Method method : mArr2) {
  59. System.out.println(method);
  60. }
  61. }
  62. }
  63. package com.itheima.demo5_反射之操作成员方法;
  64. import java.lang.reflect.Method;
  65. /**
  66. * @Author:pengzhilin
  67. * @Date: 2020/5/14 11:33
  68. */
  69. public class Test2 {
  70. public static void main(String[] args) throws Exception {
  71. /*
  72. Method getDeclaredMethod(String name,Class...args); 获取任意修饰符修饰的单个成员方法\
  73. Method[] getDeclaredMethods(); 获取所有成员方法
  74. 通过反射技术执行成员方法:
  75. Method对象常用方法
  76. * Object invoke(Object obj, Object... args)
  77. * 参数1: 调用该方法的对象
  78. * 参数2:调用方法时传递的实际参数,如果方法没有参数,就不传
  79. * void setAccessible(true)
  80. 设置"暴力访问"——是否取消权限检查,true取消权限检查,false表示不取消
  81. */
  82. // 0.获取Student类的Class对象
  83. Class<?> c = Class.forName("com.itheima.demo5_反射之操作成员方法.Student");
  84. // 1.通过反射获取public修饰的成员方法对象,并通过反射执行该方法
  85. // 1.1 通过反射获取public修饰的成员方法对象
  86. Method show1M = c.getDeclaredMethod("show1", String.class, int.class);
  87. // 1.2 通过反射执行该方法
  88. Student stu = new Student();// 使用反射创建对象:通过反射获取构造方法对象,执行该构造方法
  89. show1M.invoke(stu,"itheima",14);
  90. System.out.println("=======================");
  91. // 2.通过反射获取private修饰的成员方法对象,并通过反射执行该方法
  92. // 2.1 通过反射获取private修饰的成员方法对象
  93. Method show3M = c.getDeclaredMethod("show3");
  94. // 2.2 通过反射执行该方法
  95. // 设置暴力反射
  96. show3M.setAccessible(true);
  97. show3M.invoke(stu);
  98. }
  99. }

小结

知识点—反射之操作成员变量【自学】

目标

  • 通过反射获取类的成员变量,并访问成员变量

路径

  • Field类概述
  • 通过反射获取类的成员变量
  • 通过反射访问成员变量

讲解

Field类概述

  1. 反射之操作成员变量的目的
  2. * 通过Field对象给对应的成员变量赋值和取值
  3. Field类概述
  4. * 每一个成员变量都是一个Field类的对象。

通过反射获取类的成员变量

  1. Class类中与Field相关的方法
  2. * Field getField(String name);
  3. * 根据成员变量名获得对应Field对象,只能获得public修饰
  4. * Field getDeclaredField(String name);
  5. * 根据成员变量名获得对应Field对象,包括publicprotected、(默认)、private
  6. * Field[] getFields();
  7. * 获得所有的成员变量对应的Field对象,只能获得public
  8. * Field[] getDeclaredFields();
  9. * 获得所有的成员变量对应的Field对象,包括publicprotected、(默认)、private

通过反射访问成员变量

  1. Field对象常用方法
  2. void set(Object obj, Object value)
  3. void setInt(Object obj, int i)
  4. void setLong(Object obj, long l)
  5. void setBoolean(Object obj, boolean z)
  6. void setDouble(Object obj, double d)
  7. Object get(Object obj)
  8. int getInt(Object obj)
  9. long getLong(Object obj)
  10. boolean getBoolean(Object ob)
  11. double getDouble(Object obj)
  12. void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。
  13. Class getType(); 获取属性的类型,返回Class对象。

setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法。

getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法。

示例代码

  1. package com.itheima.demo6_反射之操作成员变量;
  2. /**
  3. * @Author:pengzhilin
  4. * @Date: 2020/5/14 10:13
  5. */
  6. public class Student {
  7. public String name;// 姓名
  8. public int age;// 年龄
  9. private String sex;// 性别
  10. @Override
  11. public String toString() {
  12. return "Student{" +
  13. "name='" + name + '\'' +
  14. ", age=" + age +
  15. ", sex='" + sex + '\'' +
  16. '}';
  17. }
  18. }
  1. public class Test1 {
  2. public static void main(String[] args) throws Exception{
  3. /*
  4. 反射之操作成员变量:
  5. - Field类概述 : 每一个成员变量都是一个Field类的对象。
  6. - 通过反射获取类的成员变量
  7. Class类中与Field相关的方法
  8. * Field getField(String name);获取单个public修饰的成员变量
  9. * 根据成员变量名获得对应Field对象,只能获得public修饰
  10. * Field getDeclaredField(String name);获取单个任意修饰符修饰的成员变量
  11. * 根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的
  12. * Field[] getFields();获取所有的public修饰的成员变量
  13. * 获得所有的成员变量对应的Field对象,只能获得public的
  14. * Field[] getDeclaredFields();获取所有的成员变量
  15. * 获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的
  16. 结论:
  17. Field getDeclaredField(String name);获取单个任意修饰符修饰的成员变量
  18. 参数:成员变量名 字符串类型
  19. Field[] getDeclaredFields();获取所有的成员变量
  20. - 通过反射访问成员变量
  21. */
  22. // 通过反射获取类的成员变量
  23. // 1.获取Student类的Class对象
  24. Class<?> c = Class.forName("com.itheima.demo6_反射之操作成员变量.Student");
  25. // 2. 获取单个成员变量的Field对象
  26. // 2.1 获取单个public修饰的成员变量
  27. Field nameF = c.getDeclaredField("name");
  28. System.out.println(nameF);
  29. // 2.2 获取单个private修饰的成员变量
  30. Field sexF = c.getDeclaredField("sex");
  31. System.out.println(sexF);
  32. System.out.println("==============================================");
  33. // 3.获取所有的成员变量的Field对象
  34. Field[] fieldArr = c.getDeclaredFields();
  35. for (Field field : fieldArr) {
  36. System.out.println(field);
  37. }
  38. }
  39. }
  40. public class Test2 {
  41. public static void main(String[] args) throws Exception {
  42. /*
  43. 通过反射获取类的成员变量
  44. Field getDeclaredField(String name);获取单个任意修饰符修饰的成员变量
  45. 参数:成员变量名 字符串类型
  46. Field[] getDeclaredFields();获取所有的成员变量
  47. 通过反射访问成员变量:
  48. Field对象常用方法
  49. 为成员变量设置值的方法
  50. void set(Object obj, Object value) 记住
  51. 参数1: 要赋值属性的对象
  52. 参数2: 属性具体的值
  53. 获取成员变量值的方法
  54. Object get(Object obj) 记住
  55. 参数: 要获取属性值的对象
  56. 返回值: 属性具体的值
  57. void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。 记住
  58. Class getType(); 获取属性的类型,返回Class对象。
  59. */
  60. // 通过反射获取类的成员变量
  61. // 1.获取Student类的Class对象
  62. Class<?> c = Class.forName("com.itheima.demo6_反射之操作成员变量.Student");
  63. // 2. 获取单个成员变量的Field对象
  64. // 2.1 获取单个public修饰的成员变量
  65. Field nameF = c.getDeclaredField("name");
  66. // 2.2 通过反射为name属性赋值
  67. Student stu = new Student();
  68. nameF.set(stu,"张三");
  69. Field ageF = c.getDeclaredField("age");
  70. // ageF.set(stu,18);
  71. ageF.setInt(stu,19);
  72. System.out.println(stu);// Student{name='张三', age=18, sex='null'}
  73. // 2.3 获取某个属性的值
  74. System.out.println(nameF.get(stu));// 张三
  75. System.out.println(ageF.get(stu));// 19
  76. // 2.2 获取单个private修饰的成员变量
  77. Field sexF = c.getDeclaredField("sex");
  78. // 暴力反射
  79. sexF.setAccessible(true);
  80. sexF.set(stu,"李四");
  81. // 获取
  82. System.out.println(sexF.get(stu));// 李四
  83. // 获取nameF属性的类型
  84. Class<?> c1 = nameF.getType();
  85. System.out.println(c1);// class java.lang.String
  86. }
  87. }

小结

第三章 注解

知识点-注解概述

目标

  • 掌握什么是注解, 注解的作用

路径

  • 注解概述
  • 注解的作用

讲解

注解概述

  • 注解(annotation),是一种代码级别的说明,和类 接口平级关系.

    • 注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无标记,看你的程序有什么标记,就去干相应的事

    • 我们之前使用过的注解:
      1).@Override:子类重写方法时——编译时起作用
      2).@FunctionalInterface:函数式接口——编译时起作用
      3).@Test:JUnit的测试注解——运行时起作用

注解的作用

  • 生成帮助文档@author和@version

  • 执行编译期的检查 例如:@Override

  • 框架的配置(框架=代码+配置)

    • 具体使用请关注框架课程的内容的学习。

小结

  1. 注解用在“源码中”,作为一个“标记”。给“注解解析器”看的,告诉“注解解析器”怎样编译、运行下面的代码。
  2. 开发中,我们一般都是使用注解

知识点-JDK提供的三个基本的注解

目标

  • 掌握JDK中提供的三个基本的注解

路径

  • 三个基本的注解

讲解

  1. @Override:描述方法的重写.
  2. @SuppressWarnings:压制\忽略警告.
  3. @Deprecated:标记过时

小结

  1. @Override: 重写父类的方法
  2. @SuppressWarnings: 压制警告
  3. @Deprecated: 标记方法的过时

知识点-自定义注解

目标

  • 掌握自定义注解和定义注解属性

路径

  • 自定义注解格式
  • 定义注解属性

讲解

自定义注解语法

  1. public @interface 注解名{
  2. 属性
  3. }
  • 示例代码
  1. /**
  2. * 定义了注解
  3. *
  4. */
  5. public @interface Annotation01 {
  6. }

注解属性

格式
  • 数据类型 属性名();

属性类型
  1. 1.基本类型
  2. 2.String
  3. 3.Class类型
  4. 4.注解类型
  5. 5. 枚举类型
  6. 6.以上类型的一维数组类型
  • 示例代码
  1. public @interface Annotation01 {
  2. // 1.基本数据类型(4类8种)
  3. int a();
  4. double b();
  5. // 2.String类型
  6. String c();
  7. // 3.Class类型
  8. Class d();
  9. // 4.注解类型
  10. Annotation02 f();
  11. // 5.枚举类型
  12. Sex e();
  13. // 6.以上类型的一维数组类型
  14. int[] g();
  15. double[] h();
  16. String[] i();
  17. Sex[] j();
  18. Annotation02[] k();
  19. }

小结

知识点— 使用注解并给注解属性赋值

目标

  • 能够使用注解并给注解属性赋值

路径

  • 使用注解并给注解属性赋值

讲解

  1. 使用注解:
  2. 如果一个注解中有属性,那么使用注解的时候一定要给注解属性赋值
  3. 如果一个注解没用属性,那么就不需要给注解属性赋值,直接使用即可
  4. 如何给注解属性赋值:
  5. @注解名(属性名=值,属性名2=值2)

案例演示
  1. public @interface MyAnnotation1 {
  2. // 不定义注解属性
  3. }
  4. public @interface MyAnnotation2 {
  5. int a();
  6. String[] b();
  7. }
  8. @MyAnnotation1()
  9. public class Test1 {
  10. @MyAnnotation1
  11. public static void main(String[] args) {
  12. /*
  13. 使用注解:
  14. 不带属性的注解: 注解中没有定义属性,或者里面的属性已经给了默认值
  15. 在需要使用该注解的地方,写上 @注解名 即可 或者 @注解名()
  16. */
  17. }
  18. }
  19. @MyAnnotation2(a=18,b={"itheima","itcast"})
  20. public class Test2 {
  21. @MyAnnotation2(a=18,b={"itheima","itcast"})
  22. public static void main(String[] args) {
  23. /*
  24. 使用注解:
  25. 带有属性的注解: 注解中定义了属性,并这些属性没有给默认值
  26. 标准格式: @注解名(属性名=属性值,属性名=属性值,....)
  27. */
  28. }
  29. }

小结

知识点—给注解属性赋值的注意事项

目标

  • 理解给注解属性赋值的注意事项

路径

讲解

  • 一旦注解有属性了,使用注解的时候,属性必须有值
  • 若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
  • 如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
  • 注解属性可以有默认值 格式:属性类型 属性名() defaul t 默认值;
  1. public @interface MyAnnotation1 {
  2. int a();
  3. }
  4. public @interface MyAnnotation2 {
  5. int[] arr();
  6. }
  7. public @interface MyAnnotation3 {
  8. int value();
  9. }
  10. public @interface MyAnnotation33 {
  11. String[] value();
  12. }
  13. public @interface MyAnnotation4 {
  14. int a() default 10;
  15. }
  16. public class Test {
  17. public static void main(String[] args) {
  18. /*
  19. 给注解属性赋值的注意事项:
  20. - 一旦注解有属性了,使用注解的时候,属性必须有值
  21. - 若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
  22. - 如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
  23. - 注解属性可以有默认值 格式:属性类型 属性名() defaul t 默认值;
  24. */
  25. }
  26. // 注解属性可以有默认值 格式:属性类型 属性名() defaul t 默认值;
  27. //@MyAnnotation4
  28. //@MyAnnotation4()
  29. @MyAnnotation4(a = 100)
  30. public static void method4(){
  31. }
  32. // 若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
  33. //如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
  34. //@MyAnnotation33(value={"itheima","itcast"})
  35. //@MyAnnotation33(value={"itheima"})
  36. //@MyAnnotation33(value="itheima")
  37. @MyAnnotation33("itheima")
  38. public static void method33(){
  39. }
  40. // 如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
  41. //@MyAnnotation3(value=10)
  42. @MyAnnotation3(10)
  43. public static void method3(){
  44. }
  45. // 若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
  46. // @MyAnnotation2(arr={10,20,30})
  47. // @MyAnnotation2(arr={10})
  48. @MyAnnotation2(arr=10)
  49. public static void method2(){
  50. }
  51. // 一旦注解有属性了,使用注解的时候,属性必须有值
  52. @MyAnnotation1(a = 10)
  53. public static void method1(){
  54. }
  55. }

小结

知识点-元注解

目标

  • 能够说出常用的元注解及其作用

路径

  • 什么是元注解
  • 常见的元注解

讲解

什么是元注解

  1. 定义在注解上的注解

常见的元注解

  1. @Target:表示该注解作用在什么上面(位置),默认注解可以在任何位置. 值为:ElementType的枚举值
  2. METHOD:方法
  3. TYPE:类 接口
  4. FIELD:字段
  5. CONSTRUCTOR:构造方法声明
  6. @Retention:定义该注解保留到那个代码阶段, 值为:RetentionPolicy类型,默认只在源码阶段保留
  7. SOURCE:只在源码上保留(默认)
  8. CLASS:在源码和字节码上保留
  9. RUNTIME:在所有的阶段都保留

.java (源码阶段) ——编译—-> .class(字节码阶段) ——加载内存—> 运行(RUNTIME)

案例:

  1. // 标准格式:
  2. //@Target(value={ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.LOCAL_VARIABLE})
  3. //@Retention(value= RetentionPolicy.RUNTIME)
  4. // 省略格式
  5. @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.LOCAL_VARIABLE})
  6. @Retention(RetentionPolicy.RUNTIME)
  7. public @interface MyAnnotation1 {// 默认该注解可以在任何位置使用
  8. }
  9. @MyAnnotation1
  10. public class Test1 {
  11. @MyAnnotation1
  12. int age = 18;
  13. @MyAnnotation1
  14. public static void main(String[] args) {
  15. @MyAnnotation1
  16. int num1 = 10;// 局部变量
  17. // jdk中的@Override
  18. // @Override // 编译报错
  19. int num2 = 10;// 局部变量
  20. }
  21. @Override
  22. public String toString() {
  23. return super.toString();
  24. }
  25. }

小结

知识点-注解解析

目标

  • 理解常见注解解析方法

路径

  • 使用注解解析

讲解

java.lang.reflect.AnnotatedElement接口: Class、Method、Field、Constructor等实现了AnnotatedElement

  • T getAnnotation(ClassannotationType):得到指定类型的注解引用。没有返回null。

  • boolean isAnnotationPresent(Class<?extends Annotation> annotationType):判断指定的注解有没有。

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface MyAnnotation1 {
  4. String name();
  5. int age();
  6. }
  7. public class Test {
  8. @MyAnnotation1(name="张三",age=18)
  9. public void show1(){
  10. System.out.println("show1方法执行了....");
  11. }
  12. public void show2(){
  13. System.out.println("show2方法执行了....");
  14. }
  15. public static void main(String[] args) throws Exception{
  16. /*
  17. java.lang.reflect.AnnotatedElement接口: Class、Method、Field、Constructor等实现了AnnotatedElement
  18. - T getAnnotation(Class<T> annotationType):得到指定类型的注解引用。没有返回null。
  19. - boolean isAnnotationPresent(Class<?extends Annotation> annotationType):判断指定的注解有没有。
  20. */
  21. // 需求:1.获取show1方法上面的注解对象
  22. // 1.1 得到Test类的Class对象
  23. Class<?> c = Class.forName("com.itheima.demo12_注解解析.Test");
  24. // 1.2 获得show1方法的Method对象
  25. Method show1M = c.getDeclaredMethod("show1");
  26. // 1.3 根据Method对象调用getAnnotation()方法得到注解对象
  27. MyAnnotation1 a1 = show1M.getAnnotation(MyAnnotation1.class);
  28. System.out.println(a1.name());
  29. System.out.println(a1.age());
  30. System.out.println("======================");
  31. // 2.需求: 判断某个方法上是否有MyAnnotation1注解
  32. // 判断show1方法上是否有MyAnnotation1注解
  33. boolean res1 = show1M.isAnnotationPresent(MyAnnotation1.class);
  34. System.out.println(res1);// true
  35. // 判断show2方法上是否有MyAnnotation1注解
  36. Method show2M = c.getDeclaredMethod("show2");
  37. boolean res2 = show2M.isAnnotationPresent(MyAnnotation1.class);
  38. System.out.println(res2);// false
  39. }
  40. }

小结

实操—完成注解的MyTest案例

需求

  1. 在一个类(测试类,TestDemo)中有三个方法,其中两个方法上有@MyTest,另一个没有.还有一个主测试类(MainTest)中有一个main方法. main方法中,让TestDemo类中含有@MyTest方法执行. 自定义@MyTest, 模拟单元测试.

思路分析

  1. 定义两个类和一个注解

  2. 在MainTest的main()方法里面:
    //1.获得TestDemo字节码对象
    //2.反射获得TestDemo里面的所有的方法
    //3.遍历方法对象的数组. 判断是否有@MyTest(isAnnotationPresent)
    //4.有就执行(method.invoke())

代码实现

  • MyTest.java
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface MyTest {
  4. }
  • TestDemo.java
  1. public class TestDemo {
  2. @MyTest
  3. public void show1(){
  4. System.out.println("show1方法执行了...");
  5. }
  6. @MyTest
  7. public void show2(){
  8. System.out.println("show2方法执行了...");
  9. }
  10. public void show3(){
  11. System.out.println("show3方法执行了...");
  12. }
  13. }
  • MainTest.java
  1. public class MainTest {
  2. public static void main(String[] args) throws Exception {
  3. // 让第一个类中含有@MyTest注解的方法执行
  4. // 1.获取TestDemo类的字节码对象
  5. Class<TestDemo> clazz = TestDemo.class;
  6. // 2.使用字节码对象获取该类中所有方法对象
  7. Method[] methods = clazz.getDeclaredMethods();
  8. // 3.循环遍历所有方法对象
  9. for (Method method : methods) {
  10. // 4.在循环中,判断遍历出来的方法对象是否含有@MyTest注解
  11. boolean res = method.isAnnotationPresent(MyTest.class);
  12. if (res) {
  13. // 5.如果有,就调用该方法执行
  14. method.invoke(clazz.newInstance());
  15. }
  16. }
  17. }
  18. }

小结

第四章 动态代理

目标

  • 能够使用动态代理生成一个代理对象

路径

  • 代理模式概念
  • 动态代理
  • 动态代理相关api介绍
  • 案例演示

讲解

代理模式概述

为什么要有“代理”?生活中就有很多代理的例子,例如,我现在需要出国,但是我不愿意自己去办签证、预定机票和酒店(觉得麻烦 ,那么就可以找旅行社去帮我办,这时候旅行社就是代理,而我自己就是被代理了。

代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者, 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)

静态代理:

  1. public interface Happy {// 协议,被代理者需要代理的方法,就定义在这里,然后让代理者和被代理者去实现
  2. // 被代理者实现: 为了确保和代理者实现的方法一致
  3. // 代理者实现: 为了增强被代理者的这些方法
  4. public abstract void happy();
  5. }
  6. public class JinLian implements Happy {
  7. public void happy(){
  8. System.out.println("金莲在happy...");
  9. }
  10. }
  11. public class WangPo implements Happy{
  12. // 成员变量
  13. JinLian jl;
  14. // 构造方法
  15. public WangPo(JinLian jl) {
  16. this.jl = jl;
  17. }
  18. // 成员方法
  19. @Override
  20. public void happy() {
  21. System.out.println("王婆以做衣服的名义开好房间,并把2人约到房间里...");
  22. // 金莲happy
  23. jl.happy();
  24. System.out.println("王婆打扫战场...");
  25. }
  26. }
  27. public class XiMen {
  28. public static void main(String[] args) {
  29. /*
  30. 案例: 金莲要找西门happy
  31. 代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者,
  32. 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)
  33. */
  34. // 不请代理: 金莲直接找西门happy
  35. // 创建金莲对象
  36. JinLian jl = new JinLian();
  37. // happy
  38. // jl.happy();
  39. // 请代理: 静态代理,代理类真实存在
  40. Happy wp = new WangPo(jl);// wp:代理对象 WangPo类: 代理类 Happy接口: 协议 JinLian: 被代理类
  41. wp.happy();
  42. }
  43. }

动态代理介绍

  • 概述 : 动态代理就是直接通过反射生成一个代理对象,代理对象所属的类是不需要存在的

  • 动态代理的获取:
    jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象

动态代理相关api介绍

Java.lang.reflect.Proxy类可以直接生成一个代理对象

  • Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象

    • 参数1:ClassLoader loader 被代理对象的类加载器
    • 参数2:Class<?>[] interfaces 被代理对象的要实现的接口
    • 参数3:InvocationHandler h (接口)执行处理接口
    • 返回值: 代理对象
    • 前2个参数是为了帮助在jvm内部生成被代理对象的代理对象,第3个参数,用来监听代理对象调用方法,帮助我们调用方法
  • InvocationHandler中的Object invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行

    • 参数1:代理对象(慎用)
    • 参数2:当前执行的方法
    • 参数3:当前执行的方法运行时传递过来的参数
    • 返回值:当前方法执行的返回值

案例演示

案例1: 代理方法无参数
  1. public interface Happy {// 协议,被代理者需要代理的方法,就定义在这里,然后让代理者和被代理者去实现
  2. // 被代理者实现: 为了确保和代理者实现的方法一致
  3. // 代理者实现: 为了增强被代理者的这些方法
  4. public abstract void happy();
  5. }
  6. public class JinLian implements Happy {
  7. public void happy(){
  8. System.out.println("金莲在happy...");
  9. }
  10. }
  11. public class XiMen {
  12. public static void main(String[] args) {
  13. /*
  14. 案例: 金莲要找西门happy
  15. 代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者,
  16. 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)
  17. */
  18. // 不请代理: 金莲直接找西门happy
  19. // 创建金莲对象
  20. JinLian jl = new JinLian();
  21. // happy
  22. // jl.happy();
  23. // 请代理: 静态代理,代理类真实存在
  24. Happy wp = new WangPo(jl);// wp:代理对象 WangPo类: 代理类 Happy接口: 协议 JinLian: 被代理类
  25. wp.happy();
  26. /*
  27. 问题:
  28. 1.金莲不方便直接找西门happy
  29. 2.金莲的happy方法需要增强一下,例如:happy之前需要开房,happy之后需要打扫战场
  30. 静态代理: 代理类是真实存在的,通过代理类产生代理对象
  31. 动态代理: 代理类是不真实存在的,在程序运行中,直接产生代理对象
  32. 前提: 被代理类需要实现接口
  33. 动态代理实现获取代理对象:
  34. jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
  35. Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
  36. 参数1loader:被代理类的类加载器
  37. 参数2interfaces: 被代理类所有实现的接口的Class对象
  38. 参数3InvocationHandler: 执行处理类
  39. 前2个参数是为了帮助在jvm内部生成被代理类的代理对象,第3个参数用来监听代理对象调用的方法,帮助我们代理对象调用方法
  40. */
  41. System.out.println("=========================================");
  42. // 使用动态代理直接产生金莲的代理对象
  43. // 动态代理: 代理类是不真实存在的,但代理类是一定实现了被代理类的接口的
  44. // p:动态代理产生的代理对象 代理类是不真实存在的
  45. Happy p = (Happy) Proxy.newProxyInstance(JinLian.class.getClassLoader(), JinLian.class.getInterfaces(), new InvocationHandler() {
  46. @Override
  47. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  48. // 回调方法: 当代理对象调用了方法,就会来执行该invoke方法, 在该方法中就可以增强被代理类的方法
  49. // 参数1: 生成的代理对象 这里就是p这个代理对象 (慎用)
  50. // 参数2: 当前代理对象执行的方法 这里method就是happy()方法对象
  51. // 参数3: 当前代理对象执行的方法,传入的实际参数
  52. // 返回值:当前代理对象执行的方法的返回值
  53. // System.out.println("invoke");
  54. // 王婆开房
  55. System.out.println("王婆以做衣服的名义开好房间,把2人约到房间...");
  56. // 金莲happy
  57. method.invoke(jl);
  58. // 王婆打扫
  59. System.out.println("王婆打印战场...");
  60. return null;
  61. }
  62. });
  63. // 代理happy
  64. p.happy();// 无参数
  65. }
  66. }

案例2: 代理方法有参数和代理多个方法
  1. public class Test {
  2. public static void main(String[] args) {
  3. /*
  4. 需求:
  5. 对List接口进行代理,以前的remove(Object obj)方法是删除集合中第一次出现的元素
  6. (比如集合中有多个“abc”,调用remove(“abc”)后只会删除一个元素)。
  7. 代理后,要求在调用remove(Object obj)方法后,能够删除集合中所有匹配的元素。【动态代理】
  8. 动态代理步骤:
  9. 1.使用Proxy调用newProxyInstance()方法动态获取代理对象
  10. 2.在InvocationHandler中的invoke方法进行增强代理的方法
  11. */
  12. // ArrayList看成被代理类
  13. ArrayList<String> list = new ArrayList<>();// JinLian
  14. list.add("abc");
  15. list.add("bac");
  16. list.add("cba");
  17. list.add("abc");
  18. list.add("abc");
  19. list.add("abc");
  20. list.add("abc");
  21. System.out.println("删除前:"+list);// [abc, bac, cba, abc, abc, abc, abc]
  22. // 获取代理对象
  23. List<String> proxy = (List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(),ArrayList.class.getInterfaces(), new InvocationHandler() {
  24. @Override
  25. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  26. // 代理对象调用方法就会来到这里
  27. Object res = method.invoke(list, args);
  28. if (method.getName().equals("remove")){
  29. // 迭代器循环删除
  30. Iterator<String> it = list.iterator();
  31. while (it.hasNext()) {
  32. String e = it.next();
  33. if (e.equals(args[0])){// false
  34. it.remove();
  35. }
  36. }
  37. }
  38. if (method.getName().equals("set")){
  39. System.out.println("hhhhhhhhh....");
  40. }
  41. return res;
  42. }
  43. });
  44. // 代理对象.remover("abc"); // [bac, cba]
  45. boolean res = proxy.remove("abc");// 拆箱
  46. System.out.println("res:"+res);// true
  47. System.out.println("删除后:"+list);// [bac, cba]
  48. // 调用proxy调用set方法设置值
  49. String res2 = proxy.set(0, "acb");
  50. System.out.println("res2:"+res2);// res2: bac
  51. System.out.println("设置后:"+list);// [bac, cba]
  52. // 未使用代理
  53. // list.remove("abc");
  54. // System.out.println("删除后:"+list);// [bac, cba, abc, abc, abc, abc]
  55. }
  56. }

小结

第五章JDK8新特性

知识点—方法引用

目标

  • 什么是方法引用,方法引用的使用场景

路径

  • 方法引用概述

讲解

方法引用概述

  • 方法引用使用一对冒号 :: , 方法引用就是用来在一定的情况下,替换Lambda表达式

方法引用基本使用

  • 使用场景:

    • 如果一个Lambda表达式大括号中的代码和另一个方法中的代码一模一样,那么就可以使用方法引用把该方法引过来,从而替换Lambda表达式
    • 如果一个Lambda表达式大括号中的代码就是调用另一方法,那么就可以使用方法引用把该方法引过来,从而替换Lambda表达式
  1. public class Demo {
  2. public static void printStr(){
  3. System.out.println("任务执行了...");
  4. }
  5. public static void main(String[] args) {
  6. // 创建线程并启动线程
  7. // 1.匿名内部类的方式
  8. new Thread(new Runnable() {
  9. @Override
  10. public void run() {
  11. System.out.println("任务执行了...");
  12. }
  13. }).start();
  14. // 2.Lambda表达式的方式
  15. new Thread(()->{System.out.println("任务执行了...");}).start();// 这个Lambda表达式大括号中的代码和Demo类的printStr()方法一模一样,符合方法引用替换Lambda表达式的场景
  16. new Thread(()->{Demo.printStr();}).start();// 这个Lambda表达的大括号中其实就是调用Demo类的printStr()方法,符合方法引用替换Lambda表达式的场景
  17. // 3.方法引用的方式:
  18. new Thread(Demo::printStr).start();
  19. }
  20. }

小结

知识点—方法引用的分类

目标

  • 能够正确书写方法引用

路径

  • 构造方法引用
  • 静态方法引用
  • 对象成员方法引用
  • 类的成员方法引用

讲解

构造方法引用

  1. public class Test2 {
  2. public static void main(String[] args) {
  3. //创建集合
  4. ArrayList<String> list = new ArrayList<>();
  5. list.add("杨紫");
  6. list.add("迪丽热巴");
  7. list.add("陈钰琪");
  8. // 需求: 把集合中的元素转换为Person对象,打印输出
  9. list.stream().map(s-> new Person(s)).forEach(s-> System.out.println(s));
  10. System.out.println("======================");
  11. list.stream().map(Person::new).forEach(s-> System.out.println(s));
  12. }
  13. }

静态方法引用

  1. public class Test2 {
  2. public static void main(String[] args) {
  3. //创建集合
  4. ArrayList<String> list = new ArrayList<>();
  5. list.add("110");
  6. list.add("111");
  7. list.add("112");
  8. // 需求:把集合中的元素转换为int类型,打印输出
  9. list.stream().map(s-> Integer.parseInt(s)).forEach(s-> System.out.println(s));
  10. System.out.println("======================");
  11. list.stream().map(Integer::parseInt).forEach(s-> System.out.println(s));
  12. }
  13. }

对象成员方法引用

  • 成员方法有参数

    1. public class Test2 {
    2. public static void main(String[] args) {
    3. //创建集合
    4. ArrayList<String> list = new ArrayList<>();
    5. list.add("杨紫");
    6. list.add("迪丽热巴");
    7. list.add("陈钰琪");
    8. // 需求:把集合中所有元素打印输出
    9. list.stream().forEach(s-> System.out.println(s));
    10. System.out.println("=================================");
    11. list.stream().forEach(System.out::println);
    12. }
    13. }

类的成员方法引用

  • 成员方法没有参数

    1. public class Test2 {
    2. public static void main(String[] args) {
    3. //创建集合
    4. ArrayList<String> list = new ArrayList<>();
    5. list.add("杨紫");
    6. list.add("迪丽热巴");
    7. list.add("陈钰琪");
    8. // 需求: 把集合中的元素转换为该元素对应的字符长度,打印输出
    9. list.stream().map(s->s.length()).forEach(System.out::println);
    10. System.out.println("=================================");
    11. //会默认的用参数s去调用String类中的length()方法
    12. list.stream().map(String::length).forEach(System.out::println);
    13. }
    14. }

小结

  1. 总结:使用方法引用的步骤
  2. 1.分析要写的Lambda表达式的大括号中是否就是调用另一个方法
  3. 2.如果是,就可以使用方法引用替换,如果不是,就不能使用方法引用
  4. 3.确定引用的方法类型(构造方法,成员方法,静态方法,类的成员方法)
  5. 4.按照对应的格式去引用:
  6. 构造方法: 类名::new
  7. 成员方法(有参数): 对象名::方法名
  8. 静态方法: 类名::方法名
  9. 类的成员方法\成员方法(无参数): 类名::方法名

知识点—Base64

目标

  • 会使用Base64对数据进行编码和解码

路径

  • Base64概述
  • Base64内嵌类和方法描述
  • Base64代码演示

讲解

Base64概述

  • Base64是jdk8提出的一个新特性,可以用来进行按照一定规则编码和解码

Base64编码和解码的相关方法

  • 编码的步骤:

    • 获取编码器
    • 调用方法进行编码
  • 解码步骤:

    • 获取解码器
    • 调用方法进行解码
  • Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:

    • 基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
    • URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
    • MIME:输出隐射到MIME友好格式。输出每行不超过76字符,并且使用’\r’并跟随’\n’作为分割。编码输出最后没有行分割。
  • 获取编码器和解码器的方法 ```java static Base64.Decoder getDecoder() 基本型 base64 解码器。 static Base64.Encoder getEncoder() 基本型 base64 编码器。

static Base64.Decoder getMimeDecoder() Mime型 base64 解码器。 static Base64.Encoder getMimeEncoder() Mime型 base64 编码器。

static Base64.Decoder getUrlDecoder() Url型 base64 解码器。 static Base64.Encoder getUrlEncoder() Url型 base64 编码器。

  1. -
  2. 编码和解码的方法:
  3. ```java
  4. Encoder编码器: encodeToString(byte[] bys)编码
  5. Decoder解码器: decode(String str) 解码

案例演示

  • 基本
  1. public class Test1 {
  2. public static void main(String[] args) {
  3. // 使用基本型的编码器和解码器对数据进行编码和解码:
  4. // 1.获取编码器
  5. Base64.Encoder encoder = Base64.getEncoder();
  6. // 2.对字符串进行编码
  7. String str = "name=中国?password=123456";
  8. String str1 = encoder.encodeToString(str.getBytes());
  9. // 3.打印输出编码后的字符串
  10. System.out.println("编码后的字符串:"+str1);
  11. // 4.获取解码器
  12. Base64.Decoder decoder = Base64.getDecoder();
  13. // 5.对编码后的字符串进行解码
  14. byte[] bys = decoder.decode(str1);
  15. String str2 = new String(bys);
  16. // 6.打印输出解码后的字符串
  17. System.out.println("解码后的字符串:"+str2);
  18. }
  19. }
  • URL
  1. public class Test2 {
  2. public static void main(String[] args) {
  3. // 使用URL型的编码器和解码器对数据进行编码和解码:
  4. // 1.获取编码器
  5. Base64.Encoder encoder = Base64.getUrlEncoder();
  6. // 2.对字符串进行编码
  7. String str = "name=中国?password=123456";
  8. String str1 = encoder.encodeToString(str.getBytes());
  9. // 3.打印输出编码后的字符串
  10. System.out.println("编码后的字符串:"+str1);
  11. // 4.获取解码器
  12. Base64.Decoder decoder = Base64.getUrlDecoder();
  13. // 5.对编码后的字符串进行解码
  14. byte[] bys = decoder.decode(str1);
  15. String str2 = new String(bys);
  16. // 6.打印输出解码后的字符串
  17. System.out.println("解码后的字符串:"+str2);
  18. }
  19. }
  • MIME
  1. public class Test3 {
  2. public static void main(String[] args) {
  3. // 使用MIME型的编码器和解码器对数据进行编码和解码:
  4. // 1.获取编码器
  5. Base64.Encoder encoder = Base64.getMimeEncoder();
  6. // 2.对字符串进行编码
  7. String str = "";
  8. for (int i = 0; i < 100; i++) {
  9. str += i;
  10. }
  11. System.out.println("编码前的字符串:"+str);
  12. String str1 = encoder.encodeToString(str.getBytes());
  13. // 3.打印输出编码后的字符串
  14. System.out.println("编码后的字符串:"+str1);
  15. // 4.获取解码器
  16. Base64.Decoder decoder = Base64.getMimeDecoder();
  17. // 5.对编码后的字符串进行解码
  18. byte[] bys = decoder.decode(str1);
  19. String str2 = new String(bys);
  20. // 6.打印输出解码后的字符串
  21. System.out.println("解码后的字符串:"+str2);
  22. }
  23. }

小结

总结

  1. - 能够使用Junit进行单元测试
  2. 拷贝Junitjar包到模块的lib文件夹下
  3. 添加到classpath路径中
  4. 在测试方法上面使用@Test注解修饰
  5. 执行
  6. - 能够通过反射技术获取Class字节码对象
  7. 类名.class
  8. 对象名.getClass()
  9. Class.forName(类的全路径)
  10. - 能够通过反射技术获取构造方法对象,并创建对象。
  11. getDeclaredConstructor(Class... parameterType)
  12. getDeclaredConstructors()
  13. newInstance(Object... initargs)
  14. void setAccessible(true)
  15. - 能够通过反射获取成员方法对象,并且调用方法。
  16. getDeclaredMethod(String name,Class... parameterType)
  17. getDeclaredMethods()
  18. invoke(Object obj,Object... initargs)
  19. void setAccessible(true)
  20. - 能够通过反射获取属性对象,并且能够给对象的属性赋值和取值。
  21. getDeclaredField(String name)
  22. Field[] getDeclaredFields();
  23. set(Object obj,Object value)
  24. get(Object obj)
  25. void setAccessible(true)
  26. - 能够说出注解的作用
  27. 编译检查
  28. 生成文档
  29. 框架配置
  30. - 能够自定义注解和使用注解
  31. public @interface 注解名{
  32. 数据类型 属性名();
  33. }
  34. 没有属性: @注解名 @注解名()
  35. 有属性: @注解名(属性名=属性值,属性名=属性值)
  36. 如果属性名为value,那么赋值的时候属性名可以省略
  37. 如果属性是数组类型,并且赋值的时候数组中只有一个值,那么大括号可以省略
  38. - 能够说出常用的元注解及其作用
  39. @Target 用来限制注解可以使用的位置
  40. @Retention 用来限制注解可以保留到哪个阶段
  41. - 能够解析注解并获取注解中的数据
  42. T getAnnotation(Class<T> annotationType):
  43. boolean isAnnotationPresent(Class<?extends Annotation> annotationType)
  44. - 能够完成注解的MyTest案例
  45. 获取类的字节码对象
  46. 获取所有的方法对象
  47. 遍历所有方法的对象
  48. 判断方法上是否有注解
  49. 如果有注解就执行该方法
  50. - 能够说出动态代理模式的作用
  51. 动态的生成一个代理对象,并且可以增强被代理里的方法
  52. - 能够使用Proxy的方法生成代理对象
  53. Proxy.newProxyInstance(ClassLoader c, Class[] interfaces,InvocationHandler i)
  54. - 能够使用四种方法的引用
  55. 构造方法: 类名::new
  56. 静态方法: 类名::方法名
  57. 对象成员方法(有参数): 对象::方法名
  58. 类成员方法(无参数): 类名::方法名
  59. - 能够使用Base64对基本数据、URLMIME类型进行编解码
  60. 获取编码器,对数据进行编码
  61. 获取解码器,对数据进行解码