JAVA进阶--Junit单元测试、反射--2022年9月19日
第一节 Junit单元测试
1、Junit单元测试是做什么的
测试类中方法的正确性的
2、Junit单元测试的有点是什么
Junit可以选择执行哪些测试方法,可以一键执行全部测试方法的测试
Junit可以生测试报告,如果测试良好则是绿色;如果测试失败,则是红色
单元测试中的某个方法测试失败了,不会影响其他测试方法的测试
====================================================================================================
3、Junit单元测试的实现过程是什么样的
必须导入Junit框架的jar包
定义的测试方法必须是无参数返回值,且公开的方法
测试方法使用@Test注解标记
4、Junit测试某个方法,测试全部方法怎么处理?成功的标志是什么
测试某个方法直接右键该方法启动测试
测试全部方法,可以选择类或者模块启动
红色失败,绿色通过,黄色表示方法没问题,但是预期结果不一样

1 package com.itheima.d1_junit; 2 3 /** 4 业务方法 5 */ 6 public class UserService { 7 public String loginName(String loginName , String passWord){ 8 if("admin".equals(loginName) && "123456".equals(passWord)){ 9 return "登录成功"; 10 }else { 11 return "用户名或者密码有问题"; 12 } 13 } 14 15 public void selectNames(){ 16 System.out.println(10/2); 17 System.out.println("查询全部用户名称成功~~"); 18 } 19 }

1 package com.itheima.d1_junit; 2 3 import org.junit.*; 4 5 /** 6 测试类 7 */ 8 public class TestUserService { 9 10 // 修饰实例方法的 11 @Before 12 public void before(){ 13 System.out.println("===before方法执行一次==="); 14 } 15 16 @After 17 public void after(){ 18 System.out.println("===after方法执行一次==="); 19 } 20 21 // 修饰静态方法 22 @BeforeClass 23 public static void beforeClass(){ 24 System.out.println("===beforeClass方法执行一次==="); 25 } 26 27 @AfterClass 28 public static void afterClass(){ 29 System.out.println("===afterClass方法执行一次==="); 30 } 31 32 33 /** 34 测试方法 35 注意点: 36 1、必须是公开的,无参数 无返回值的方法 37 2、测试方法必须使用@Test注解标记。 38 */ 39 @Test 40 public void testLoginName(){ 41 UserService userService = new UserService(); 42 String rs = userService.loginName("admin","123456"); 43 44 // 进行预期结果的正确性测试:断言。 45 Assert.assertEquals("您的登录业务可能出现问题", "登录成功", rs ); 46 } 47 48 @Test 49 public void testSelectNames(){ 50 UserService userService = new UserService(); 51 userService.selectNames(); 52 } 53 54 }
5、单元测试常用注解

1 package com.itheima.d1_junit; 2 3 import org.junit.*; 4 5 /** 6 测试类 7 */ 8 public class TestUserService { 9 10 // 修饰实例方法的 11 @Before 12 public void before(){ 13 System.out.println("===before方法执行一次==="); 14 } 15 16 @After 17 public void after(){ 18 System.out.println("===after方法执行一次==="); 19 } 20 21 // 修饰静态方法 22 @BeforeClass 23 public static void beforeClass(){ 24 System.out.println("===beforeClass方法执行一次==="); 25 } 26 27 @AfterClass 28 public static void afterClass(){ 29 System.out.println("===afterClass方法执行一次==="); 30 } 31 32 33 /** 34 测试方法 35 注意点: 36 1、必须是公开的,无参数 无返回值的方法 37 2、测试方法必须使用@Test注解标记。 38 */ 39 @Test 40 public void testLoginName(){ 41 UserService userService = new UserService(); 42 String rs = userService.loginName("admin","123456"); 43 44 // 进行预期结果的正确性测试:断言。 45 Assert.assertEquals("您的登录业务可能出现问题", "登录成功", rs ); 46 } 47 48 @Test 49 public void testSelectNames(){ 50 UserService userService = new UserService(); 51 userService.selectNames(); 52 } 53 54 }
第二节 反射
1、反射的基本作用、关键?
反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分
反射的核心思想和关键就是:得到编译以后的class文件对象
2、反射的第一步是什么
获取Class类对象,如此才可以解析类的全部成分
3、获取Class类的对象的三种方式
方式一:Class c1 = Class.forName("全类名");
方式二:Class c2 = 类名.class;
方式三:Class c3 = 对象.getClass();

1 package com.itmao.d2_reflect_class; 2 3 public class Student { 4 }

1 package com.itmao.d2_reflect_class; 2 3 /** 4 目标:反射的第一步:获取Class对象 5 */ 6 public class Test { 7 public static void main(String[] args) throws Exception { 8 // 1、Class类中的一个静态方法:forName(全限名:包名 + 类名) 9 10 11 // 2、类名.class 12 Class c1 = Student.class; 13 System.out.println(c1); 14 15 // 3、对象.getClass() 获取对象对应类的Class对象。 16 17 } 18 }
4、利用反射技术获取构造器对象的方式
getDeclaredConstructors()
getDeclaredConstructor(Class<?>...parameterTypes)
5、反射得到的构造器可以做什么
依然是创建对象的
public newInstance(Object...initargs)
如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象
setAccessible(boolean)
反射可以破坏封装性,私有的也可以执行了

1 package com.itheima.d3_reflect_constructor; 2 3 public class Student { 4 private String name; 5 private int age; 6 7 private Student(){ 8 System.out.println("无参数构造器执行!"); 9 } 10 11 public Student(String name, int age) { 12 System.out.println("有参数构造器执行!"); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 33 @Override 34 public String toString() { 35 return "Student{" + 36 "name='" + name + '\'' + 37 ", age=" + age + 38 '}'; 39 } 40 }

1 package com.itheima.d3_reflect_constructor; 2 3 4 import org.junit.Test; 5 6 import java.lang.reflect.Constructor; 7 8 /** 9 目标:反射_获取Constructor构造器对象. 10 11 反射的第一步是先得到Class类对象。(Class文件) 12 13 反射中Class类型获取构造器提供了很多的API: 14 1. Constructor getConstructor(Class... parameterTypes) 15 根据参数匹配获取某个构造器,只能拿public修饰的构造器,几乎不用! 16 2. Constructor getDeclaredConstructor(Class... parameterTypes) 17 根据参数匹配获取某个构造器,只要申明就可以定位,不关心权限修饰符,建议使用! 18 3. Constructor[] getConstructors() 19 获取所有的构造器,只能拿public修饰的构造器。几乎不用!!太弱了! 20 4. Constructor[] getDeclaredConstructors() 21 获取所有申明的构造器,只要你写我就能拿到,无所谓权限。建议使用!! 22 小结: 23 获取类的全部构造器对象: Constructor[] getDeclaredConstructors() 24 -- 获取所有申明的构造器,只要你写我就能拿到,无所谓权限。建议使用!! 25 获取类的某个构造器对象:Constructor getDeclaredConstructor(Class... parameterTypes) 26 -- 根据参数匹配获取某个构造器,只要申明就可以定位,不关心权限修饰符,建议使用! 27 28 */ 29 public class TestStudent01 { 30 // 1. getConstructors: 31 // 获取全部的构造器:只能获取public修饰的构造器。 32 // Constructor[] getConstructors() 33 @Test 34 public void getConstructors(){ 35 // a.第一步:获取类对象 36 Class c = Student.class; 37 // b.提取类中的全部的构造器对象(这里只能拿public修饰) 38 Constructor[] constructors = c.getConstructors(); 39 // c.遍历构造器 40 for (Constructor constructor : constructors) { 41 System.out.println(constructor.getName() + "===>" + constructor.getParameterCount()); 42 } 43 } 44 45 46 // 2.getDeclaredConstructors(): 47 // 获取全部的构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。 48 @Test 49 public void getDeclaredConstructors(){ 50 // a.第一步:获取类对象 51 Class c = Student.class; 52 // b.提取类中的全部的构造器对象 53 Constructor[] constructors = c.getDeclaredConstructors(); 54 // c.遍历构造器 55 for (Constructor constructor : constructors) { 56 System.out.println(constructor.getName() + "===>" + constructor.getParameterCount()); 57 } 58 } 59 60 // 3.getConstructor(Class... parameterTypes) 61 // 获取某个构造器:只能拿public修饰的某个构造器 62 @Test 63 public void getConstructor() throws Exception { 64 // a.第一步:获取类对象 65 Class c = Student.class; 66 // b.定位单个构造器对象 (按照参数定位无参数构造器 只能拿public修饰的某个构造器) 67 Constructor cons = c.getConstructor(); 68 System.out.println(cons.getName() + "===>" + cons.getParameterCount()); 69 } 70 71 72 // 4.getConstructor(Class... parameterTypes) 73 // 获取某个构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。 74 @Test 75 public void getDeclaredConstructor() throws Exception { 76 // a.第一步:获取类对象 77 Class c = Student.class; 78 // b.定位单个构造器对象 (按照参数定位无参数构造器) 79 Constructor cons = c.getDeclaredConstructor(); 80 System.out.println(cons.getName() + "===>" + cons.getParameterCount()); 81 82 // c.定位某个有参构造器 83 Constructor cons1 = c.getDeclaredConstructor(String.class, int.class); 84 System.out.println(cons1.getName() + "===>" + cons1.getParameterCount()); 85 86 } 87 88 }

1 package com.itheima.d3_reflect_constructor; 2 3 import org.junit.Test; 4 5 import java.lang.reflect.Constructor; 6 7 /** 8 目标: 反射_获取Constructor构造器然后通过这个构造器初始化对象。 9 10 反射获取Class中的构造器对象Constructor作用: 11 也是初始化并得到类的一个对象返回。 12 13 Constructor的API: 14 1. T newInstance(Object... initargs) 15 创建对象,注入构造器需要的数据。 16 2. void setAccessible(true) 17 修改访问权限,true代表暴力攻破权限,false表示保留不可访问权限(暴力反射) 18 小结: 19 可以通过定位类的构造器对象。 20 如果构造器对象没有访问权限可以通过:void setAccessible(true)打开权限 21 构造器可以通过T newInstance(Object... initargs)调用自己,传入参数! 22 */ 23 public class TestStudent02 { 24 // 1.调用构造器得到一个类的对象返回。 25 @Test 26 public void getDeclaredConstructor() throws Exception { 27 // a.第一步:获取类对象 28 Class c = Student.class; 29 // b.定位单个构造器对象 (按照参数定位无参数构造器) 30 Constructor cons = c.getDeclaredConstructor(); 31 System.out.println(cons.getName() + "===>" + cons.getParameterCount()); 32 33 // 如果遇到了私有的构造器,可以暴力反射 34 cons.setAccessible(true); // 权限被打开 35 36 Student s = (Student) cons.newInstance(); 37 System.out.println(s); 38 39 System.out.println("-------------------"); 40 41 // c.定位某个有参构造器 42 Constructor cons1 = c.getDeclaredConstructor(String.class, int.class); 43 System.out.println(cons1.getName() + "===>" + cons1.getParameterCount()); 44 45 Student s1 = (Student) cons1.newInstance("孙悟空", 1000); 46 System.out.println(s1); 47 } 48 49 50 }
6、利用反射技术获取成员变量的方式
获取类中成员变量对象的方法
getDeclaredFields()
getDeclaredFiled(String name)
7、反射得到成员变量可以做什么?
依然是在某个对象中取值和赋值
void set(Object obj,Object value)
Object get(Object obj)
8、如果某成员变量时非public的,需要打开权限(暴力反射),然后再取值、赋值
setAccessible(boolean)

1 package com.itheima.d4_reflect_field; 2 3 public class Student { 4 private String name; 5 private int age; 6 public static String schoolName; 7 public static final String COUNTTRY = "中国"; 8 9 public Student(){ 10 System.out.println("无参数构造器执行!"); 11 } 12 13 public Student(String name, int age) { 14 System.out.println("有参数构造器执行!"); 15 this.name = name; 16 this.age = age; 17 } 18 19 public String getName() { 20 return name; 21 } 22 23 public void setName(String name) { 24 this.name = name; 25 } 26 27 public int getAge() { 28 return age; 29 } 30 31 public void setAge(int age) { 32 this.age = age; 33 } 34 35 @Override 36 public String toString() { 37 return "Student{" + 38 "name='" + name + '\'' + 39 ", age=" + age + 40 '}'; 41 } 42 }

1 package com.itheima.d4_reflect_field; 2 3 import org.junit.Test; 4 5 import java.io.File; 6 import java.lang.reflect.Field; 7 8 /** 9 目标:反射_获取Field成员变量对象。 10 11 反射的第一步是先得到Class类对象。 12 13 1、Field getField(String name); 14 根据成员变量名获得对应Field对象,只能获得public修饰 15 2.Field getDeclaredField(String name); 16 根据成员变量名获得对应Field对象,只要申明了就可以得到 17 3.Field[] getFields(); 18 获得所有的成员变量对应的Field对象,只能获得public的 19 4.Field[] getDeclaredFields(); 20 获得所有的成员变量对应的Field对象,只要申明了就可以得到 21 小结: 22 获取全部成员变量:getDeclaredFields 23 获取某个成员变量:getDeclaredField 24 */ 25 public class FieldDemo01 { 26 /** 27 * 1.获取全部的成员变量。 28 * Field[] getDeclaredFields(); 29 * 获得所有的成员变量对应的Field对象,只要申明了就可以得到 30 */ 31 @Test 32 public void getDeclaredFields(){ 33 // a.定位Class对象 34 Class c = Student.class; 35 // b.定位全部成员变量 36 Field[] fields = c.getDeclaredFields(); 37 // c.遍历一下 38 for (Field field : fields) { 39 System.out.println(field.getName() + "==>" + field.getType()); 40 } 41 } 42 43 /** 44 2.获取某个成员变量对象 Field getDeclaredField(String name); 45 */ 46 @Test 47 public void getDeclaredField() throws Exception { 48 // a.定位Class对象 49 Class c = Student.class; 50 // b.根据名称定位某个成员变量 51 Field f = c.getDeclaredField("age"); 52 System.out.println(f.getName() +"===>" + f.getType()); 53 } 54 55 }

1 package com.itheima.d4_reflect_field; 2 3 import org.junit.Test; 4 5 import java.lang.reflect.Field; 6 7 /** 8 目标:反射获取成员变量: 取值和赋值。 9 10 Field的方法:给成员变量赋值和取值 11 void set(Object obj, Object value):给对象注入某个成员变量数据 12 Object get(Object obj):获取对象的成员变量的值。 13 void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。 14 Class getType(); 获取属性的类型,返回Class对象。 15 String getName(); 获取属性的名称。 16 */ 17 public class FieldDemo02 { 18 @Test 19 public void setField() throws Exception { 20 // a.反射第一步,获取类对象 21 Class c = Student.class; 22 // b.提取某个成员变量 23 Field ageF = c.getDeclaredField("age"); 24 25 ageF.setAccessible(true); // 暴力打开权限 26 27 // c.赋值 28 Student s = new Student(); 29 ageF.set(s , 18); // s.setAge(18); 30 System.out.println(s); 31 32 // d、取值 33 int age = (int) ageF.get(s); 34 System.out.println(age); 35 36 } 37 }
9、利用反射技术获取成员方法对象的方式
获取类中成员方法对象
getDeclaredMethods()
getDeclaredMethod(String name,Class<?>...parameterTypes)
10、反射得到成员方法可以做什么
依然是在某个对象中触发该方法执行
Object invoke(Object obj,Object...args)
如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行
setAccessible(boolean)

1 package com.itheima.d5_reflect_method; 2 3 public class Dog { 4 private String name ; 5 public Dog(){ 6 } 7 8 public Dog(String name) { 9 this.name = name; 10 } 11 12 public void run(){ 13 System.out.println("狗跑的贼快~~"); 14 } 15 16 private void eat(){ 17 System.out.println("狗吃骨头"); 18 } 19 20 private String eat(String name){ 21 System.out.println("狗吃" + name); 22 return "吃的很开心!"; 23 } 24 25 public static void inAddr(){ 26 System.out.println("在黑马学习Java!"); 27 } 28 29 public String getName() { 30 return name; 31 } 32 33 public void setName(String name) { 34 this.name = name; 35 } 36 37 }

1 package com.itheima.d5_reflect_method; 2 import org.junit.Test; 3 4 import java.lang.reflect.Method; 5 6 /** 7 目标:反射——获取Method方法对象 8 9 反射获取类的Method方法对象: 10 1、Method getMethod(String name,Class...args); 11 根据方法名和参数类型获得对应的方法对象,只能获得public的 12 13 2、Method getDeclaredMethod(String name,Class...args); 14 根据方法名和参数类型获得对应的方法对象,包括private的 15 16 3、Method[] getMethods(); 17 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的 18 19 4、Method[] getDeclaredMethods(); 20 获得类中的所有成员方法对象,返回数组,只获得本类申明的方法。 21 22 Method的方法执行: 23 Object invoke(Object obj, Object... args) 24 参数一:触发的是哪个对象的方法执行。 25 参数二: args:调用方法时传递的实际参数 26 */ 27 public class MethodDemo01 { 28 /** 29 * 1.获得类中的所有成员方法对象 30 */ 31 @Test 32 public void getDeclaredMethods(){ 33 // a.获取类对象 34 Class c = Dog.class; 35 // b.提取全部方法;包括私有的 36 Method[] methods = c.getDeclaredMethods(); 37 // c.遍历全部方法 38 for (Method method : methods) { 39 System.out.println(method.getName() +" 返回值类型:" + method.getReturnType() + " 参数个数:" + method.getParameterCount()); 40 } 41 } 42 43 /** 44 * 2. 获取某个方法对象 45 */ 46 @Test 47 public void getDeclardMethod() throws Exception { 48 // a.获取类对象 49 Class c = Dog.class; 50 // b.提取单个方法对象 51 Method m = c.getDeclaredMethod("eat"); 52 Method m2 = c.getDeclaredMethod("eat", String.class); 53 54 // 暴力打开权限了 55 m.setAccessible(true); 56 m2.setAccessible(true); 57 58 // c.触发方法的执行 59 Dog d = new Dog(); 60 // 注意:方法如果是没有结果回来的,那么返回的是null. 61 Object result = m.invoke(d); 62 System.out.println(result); 63 64 Object result2 = m2.invoke(d, "骨头"); 65 System.out.println(result2); 66 } 67 }
11、反射为何可以给约定了泛型的集合存入其他类型的元素?
编译成Class文件进入运行阶段的时候,泛型会自动擦除
反射是作用在运行时的技术,此时已经不存在泛型了
泛型其实就只是规范我们的代码书写而已
看下面的代码,突破我这只小菜鸡的想象

1 package com.itheima.d6_reflect_genericity; 2 3 import java.lang.reflect.Method; 4 import java.util.ArrayList; 5 6 public class ReflectDemo { 7 public static void main(String[] args) throws Exception { 8 // 需求:反射实现泛型擦除后,加入其他类型的元素 9 ArrayList<String> lists1 = new ArrayList<>(); 10 ArrayList<Integer> lists2 = new ArrayList<>(); 11 12 System.out.println(lists1.getClass()); 13 System.out.println(lists2.getClass()); 14 15 System.out.println(lists1.getClass() == lists2.getClass()); // ArrayList.class 16 17 System.out.println("---------------------------"); 18 ArrayList<Integer> lists3 = new ArrayList<>(); 19 lists3.add(23); 20 lists3.add(22); 21 // lists3.add("黑马"); 22 23 Class c = lists3.getClass(); // ArrayList.class ===> public boolean add(E e) 24 // 定位c类中的add方法 25 Method add = c.getDeclaredMethod("add", Object.class); 26 boolean rs = (boolean) add.invoke(lists3, "黑马"); 27 System.out.println(rs); 28 29 System.out.println(lists3); 30 31 ArrayList list4 = lists3; 32 list4.add("白马"); 33 list4.add(false); 34 System.out.println(lists3); 35 } 36 }
12、反射做通用框架之反射的作用
可以在运行时得到一个类的全部成分然后操作
可以破坏封装性(很突出)
也可以破坏泛型的约束性(很突出)
更重要的用途是适合:做Java高级框架
基本上主流框架都会基于反射设计一些通用技术功能

1 package com.itheima.d7_reflect_framework; 2 3 public class Student { 4 private String name; 5 private char sex; 6 private int age; 7 private String className; 8 private String hobby; 9 10 public Student(){ 11 12 } 13 14 public Student(String name, char sex, int age, String className, String hobby) { 15 this.name = name; 16 this.sex = sex; 17 this.age = age; 18 this.className = className; 19 this.hobby = hobby; 20 } 21 22 public String getName() { 23 return name; 24 } 25 26 public void setName(String name) { 27 this.name = name; 28 } 29 30 public char getSex() { 31 return sex; 32 } 33 34 public void setSex(char sex) { 35 this.sex = sex; 36 } 37 38 public int getAge() { 39 return age; 40 } 41 42 public void setAge(int age) { 43 this.age = age; 44 } 45 46 public String getClassName() { 47 return className; 48 } 49 50 public void setClassName(String className) { 51 this.className = className; 52 } 53 54 public String getHobby() { 55 return hobby; 56 } 57 58 public void setHobby(String hobby) { 59 this.hobby = hobby; 60 } 61 }

1 package com.itheima.d7_reflect_framework; 2 3 public class Teacher { 4 private String name; 5 private char sex; 6 private double salary; 7 8 public Teacher(){ 9 10 } 11 12 public Teacher(String name, char sex, double salary) { 13 this.name = name; 14 this.sex = sex; 15 this.salary = salary; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public char getSex() { 27 return sex; 28 } 29 30 public void setSex(char sex) { 31 this.sex = sex; 32 } 33 34 public double getSalary() { 35 return salary; 36 } 37 38 public void setSalary(double salary) { 39 this.salary = salary; 40 } 41 }

1 package com.itheima.d7_reflect_framework; 2 3 import java.io.FileOutputStream; 4 import java.io.PrintStream; 5 import java.lang.reflect.Field; 6 7 public class MybatisUtil { 8 /** 9 保存任意类型的对象 10 * @param obj 11 */ 12 public static void save(Object obj){ 13 try ( 14 PrintStream ps = new PrintStream(new FileOutputStream("junit-reflect-annotation-proxy-app/src/data.txt", true)); 15 ){ 16 // 1、提取这个对象的全部成员变量:只有反射可以解决 17 Class c = obj.getClass(); // c.getSimpleName()获取当前类名 c.getName获取全限名:包名+类名 18 ps.println("================" + c.getSimpleName() + "================"); 19 20 // 2、提取它的全部成员变量 21 Field[] fields = c.getDeclaredFields(); 22 // 3、获取成员变量的信息 23 for (Field field : fields) { 24 String name = field.getName(); 25 // 提取本成员变量在obj对象中的值(取值) 26 field.setAccessible(true); 27 String value = field.get(obj) + ""; 28 ps.println(name + "=" + value); 29 } 30 } catch (Exception e) { 31 e.printStackTrace(); 32 } 33 } 34 }

1 package com.itheima.d7_reflect_framework; 2 3 import java.util.Date; 4 import java.util.Properties; 5 6 /** 7 目标:提供一个通用框架,支持保存所有对象的具体信息。 8 */ 9 public class ReflectDemo { 10 public static void main(String[] args) throws Exception { 11 Student s = new Student(); 12 s.setName("猪八戒"); 13 s.setClassName("西天跑路1班"); 14 s.setAge(1000); 15 s.setHobby("吃,睡"); 16 s.setSex('男'); 17 MybatisUtil.save(s); 18 19 Teacher t = new Teacher(); 20 t.setName("波仔"); 21 t.setSex('男'); 22 t.setSalary(6000); 23 MybatisUtil.save(t); 24 } 25 }
第三节 注解
1、注解的作用
对Java中类、方法、成员变量做标记,然后进行特殊处理
例如:Junit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行
2、自定义注解

1 package com.itheima.d8_annotation; 2 3 public @interface Book { 4 String value(); // 特殊属性 5 double price() ; 6 //double price() default 9.9; 7 }

1 package com.itheima.d8_annotation; 2 3 public @interface MyBook { 4 String name(); 5 String[] authors(); 6 double price(); 7 }

1 package com.itheima.d8_annotation; 2 3 /** 4 目标:学会自定义注解。掌握其定义格式和语法。 5 */ 6 @MyBook(name="《精通JavaSE》",authors = {"黑马", "dlei"} , price = 199.5) 7 //@Book(value = "/delete") 8 // @Book("/delete") 9 @Book(value = "/delete", price = 23.5) 10 //@Book("/delete") 11 public class AnnotationDemo1 { 12 13 @MyBook(name="《精通JavaSE2》",authors = {"黑马", "dlei"} , price = 199.5) 14 private AnnotationDemo1(){ 15 16 } 17 18 @MyBook(name="《精通JavaSE1》",authors = {"黑马", "dlei"} , price = 199.5) 19 public static void main(String[] args) { 20 @MyBook(name="《精通JavaSE2》",authors = {"黑马", "dlei"} , price = 199.5) 21 int age = 21; 22 } 23 }
3、元注解是什么
注解注解的注解
@Target约束自定义注解可以标记的范围
@Retention用来约束自定义注解的存活范围,就是注解的生命周期
4、注解解析的方式
==================================================================================================
=============================================================================================

1 package com.itheima.d8_annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Target({ElementType.TYPE,ElementType.METHOD}) 9 @Retention(RetentionPolicy.RUNTIME) 10 public @interface Bookk { 11 String value(); 12 double price() default 100; 13 String[] author(); 14 }

1 package com.itheima.d8_annotation; 2 3 import org.junit.Test; 4 5 import java.lang.annotation.Annotation; 6 import java.lang.reflect.Method; 7 import java.util.Arrays; 8 9 /** 10 目标:完成注解的解析 11 */ 12 public class AnnotationDemo3 { 13 @Test 14 public void parseClass(){ 15 // a.先得到类对象 16 Class c = BookStore.class; 17 // b.判断这个类上面是否存在这个注解 18 if(c.isAnnotationPresent(Bookk.class)){ 19 //c.直接获取该注解对象 20 Bookk book = (Bookk) c.getDeclaredAnnotation(Bookk.class); 21 System.out.println(book.value()); 22 System.out.println(book.price()); 23 System.out.println(Arrays.toString(book.author())); 24 } 25 } 26 27 @Test 28 public void parseMethod() throws NoSuchMethodException { 29 // a.先得到类对象 30 Class c = BookStore.class; 31 32 Method m = c.getDeclaredMethod("test"); 33 34 // b.判断这个类上面是否存在这个注解 35 if(m.isAnnotationPresent(Bookk.class)){ 36 //c.直接获取该注解对象 37 Bookk book = (Bookk) m.getDeclaredAnnotation(Bookk.class); 38 System.out.println(book.value()); 39 System.out.println(book.price()); 40 System.out.println(Arrays.toString(book.author())); 41 } 42 } 43 } 44 45 @Bookk(value = "《情深深雨濛濛》", price = 99.9, author = {"琼瑶", "dlei"}) 46 class BookStore{ 47 48 @Bookk(value = "《三少爷的剑》", price = 399.9, author = {"古龙", "熊耀华"}) 49 public void test(){ 50 } 51 }
5、模拟Junit框架

1 package com.itheima.d8_annotation; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 public class AnnotationDemo4 { 7 public void test1(){ 8 System.out.println("===test1==="); 9 } 10 11 @MyTest 12 public void test2(){ 13 System.out.println("===test2==="); 14 } 15 16 @MyTest 17 public void test3(){ 18 System.out.println("===test3==="); 19 } 20 21 /** 22 启动菜单:有注解的才被调用。 23 */ 24 public static void main(String[] args) throws Exception { 25 AnnotationDemo4 t = new AnnotationDemo4(); 26 // a.获取类对象 27 Class c = AnnotationDemo4.class; 28 // b.提取全部方法 29 Method[] methods = c.getDeclaredMethods(); 30 // c.遍历方法,看是否有MyTest注解,有就跑它 31 for (Method method : methods) { 32 if(method.isAnnotationPresent(MyTest.class)){ 33 // 跑它 34 method.invoke(t); 35 } 36 } 37 } 38 }
第四节 动态代理
1、代理是什么
一个对象,用来对被代理对象的行为额外做一些辅助工作
2、在Java中实现动态代理的步骤是什么样的
必须存在接口
被代理对象需要实现接口
使用Proxy类提供的方法,的对象的代理对象
3、通过代理对象调用方法,执行流程是什么样的
先走向代理
代理可以为方法额外做一些辅助工作
开发真正触发对象的方法的执行
回到代理中,由代理负责返回结果给方法的调用者
===========================================================================================

1 package com.itheima.d9_proxy; 2 3 /** 4 模拟用户业务功能 5 */ 6 public interface UserService { 7 String login(String loginName , String passWord) ; 8 void selectUsers(); 9 boolean deleteUsers(); 10 void updateUsers(); 11 }

1 package com.itheima.d9_proxy; 2 3 public class UserServiceImpl implements UserService{ 4 @Override 5 public String login(String loginName, String passWord) { 6 try { 7 Thread.sleep(1000); 8 } catch (Exception e) { 9 e.printStackTrace(); 10 } 11 if("admin".equals(loginName) && "1234".equals(passWord)) { 12 return "success"; 13 } 14 return "登录名和密码可能有毛病"; 15 16 } 17 18 @Override 19 public void selectUsers() { 20 System.out.println("查询了100个用户数据!"); 21 try { 22 Thread.sleep(2000); 23 } catch (Exception e) { 24 e.printStackTrace(); 25 } 26 } 27 28 @Override 29 public boolean deleteUsers() { 30 try { 31 System.out.println("删除100个用户数据!"); 32 Thread.sleep(500); 33 return true; 34 } catch (Exception e) { 35 e.printStackTrace(); 36 return false; 37 } 38 } 39 40 @Override 41 public void updateUsers() { 42 try { 43 System.out.println("修改100个用户数据!"); 44 Thread.sleep(2500); 45 } catch (Exception e) { 46 e.printStackTrace(); 47 } 48 } 49 }

1 package com.itheima.d9_proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 /** 7 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 8 参数一:类加载器,负责加载代理类到内存中使用。 9 参数二:获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行代理 10 参数三:代理的核心处理逻辑 11 */ 12 public class ProxyUtil { 13 /** 14 生成业务对象的代理对象。 15 * @param obj 16 * @return 17 */ 18 public static <T> T getProxy(T obj) { 19 // 返回了一个代理对象了 20 return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(), 21 obj.getClass().getInterfaces(), 22 new InvocationHandler() { 23 @Override 24 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 25 // 参数一:代理对象本身。一般不管 26 // 参数二:正在被代理的方法 27 // 参数三:被代理方法,应该传入的参数 28 long startTimer = System .currentTimeMillis(); 29 // 马上触发方法的真正执行。(触发真正的业务功能) 30 Object result = method.invoke(obj, args); 31 32 long endTimer = System.currentTimeMillis(); 33 System.out.println(method.getName() + "方法耗时:" + (endTimer - startTimer) / 1000.0 + "s"); 34 35 // 把业务功能方法执行的结果返回给调用者 36 return result; 37 } 38 }); 39 } 40 }

1 package com.itheima.d9_proxy; 2 3 public class Test { 4 public static void main(String[] args) { 5 // 1、把业务对象,直接做成一个代理对象返回,代理对象的类型也是 UserService类型 6 UserService userService = ProxyUtil.getProxy(new UserServiceImpl()); 7 System.out.println(userService.login("admin", "1234")); 8 System.out.println(userService.deleteUsers()); 9 userService.selectUsers(); 10 userService.updateUsers(); // 走代理 11 } 12 }