需要学会什么?
单元测试:
目前测试方法是怎么进行的,存在什么问题?
JUnit单元测试框架:
JUnit优点:
总结:
需求:
分析:
Alt + Enter选择Add 'JUnit5.x.x' to classpath,之后点击OK即可)UserService.java
/**
* 用户服务
*/
public class UserService {
/**
* 用户登录
* @param username 用户名
* @param password 密码
* @return 登录状态
*/
public String loginName(String username, String password) {
if ("admin".equals(username) && "123456".equals(password)) {
return "登录成功!";
} else {
return "用户名或密码错误!";
}
}
/**
* 查看全部用户
*/
public void selectUsers() {
System.out.println(10 / 0);
System.out.println("查询全部用户成功!");
}
}
TestUserService.java
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* 测试用户服务类
*/
public class TestUserService {
/**
* 测试用户登录方法
* 注意:
* 1.必须是公开的 无参数 无返回值的方法
* 2.测试方法必须使用@Test注解标记
*/
@Test
public void testLoginName() {
UserService userService = new UserService();
String result = userService.loginName("admin", "123456");
// 进行预期结果的正确性测试:断言
// 期待值 实际值 期待值与实际值不符时提示信息
Assertions.assertEquals("登录成功!", result, "用户登录业务可能出现问题!");
}
/**
* 测试查看全部用户方法
*/
@Test
public void testSelectUsers() {
UserService userService = new UserService();
userService.selectUsers();
}
}
JUnit单元测试执行结果:

注意:
总结:
JUnit常用注解
| JUnit4 | JUnit5 | 说明 |
|---|---|---|
| @Test | @Test | 测试方法。 |
| @Before | @BeforeEach | 用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次。 |
| @After | @AfterEach | 用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次。 |
| @BeforeClass | @BeforeAll | 用来修饰静态方法,该方法会在所有测试方法执行之前执行一次。 |
| @AfterClass | @AfterAll | 用来修饰静态方法,该方法会在所有测试方法执行之后执行一次。 |
TestUserService.java
import org.junit.jupiter.api.*;
/**
* 测试用户服务类
*/
public class TestUserService {
@BeforeEach
public void beforeEach() {
System.out.println("===beforeEach方法执行一次===");
// 作用:如初始化I/O流
}
@AfterEach
public void afterEach() {
System.out.println("===afterEach方法执行一次===");
// 作用:如关闭I/O流
}
@BeforeAll
public static void beforeAll() {
System.out.println("===beforeAll方法执行一次===");
// 作用:如初始化静态资源
}
@AfterAll
public static void afterAll() {
System.out.println("===afterAll方法执行一次===");
// 作用:如回收静态资源
}
/**
* 测试用户登录方法
* 注意:
* 1.必须是公开的 无参数 无返回值的方法
* 2.测试方法必须使用@Test注解标记
*/
@Test
public void testLoginName() {
System.out.println("===测试用户登录方法===");
UserService userService = new UserService();
String result = userService.loginName("admin", "123456");
// 进行预期结果的正确性测试:断言
// 期待值 实际值 期待值与实际值不符时提示信息
Assertions.assertEquals("登录成功!", result, "用户登录业务可能出现问题!");
}
/**
* 测试查看全部用户方法
*/
@Test
public void testSelectUsers() {
System.out.println("===测试查看全部用户方法===");
UserService userService = new UserService();
userService.selectUsers();
}
}
JUnit常用注解执行结果:

反射的概述:
反射的关键:
反射的第一步都是先得到编译后的Class对象,然后就可以得到Class的全部成分。
HelloWorld.java -> javac -> HelloWorld.class
Class c = HelloWorld.class;
总结:
反射的第一步:获取Class类的对象
Student.java
public class Student {
}
Test.java
/**
* 目标:反射的第一步 获取Class对象
*/
public class Test {
public static void main(String[] args) throws Exception {
// 1.Class类中的一个静态方法 forName 全限名/包名+类名
Class<?> studentClass = Class.forName("com.javase.reflectclassdemo.Student");
// class com.javase.reflectclassdemo.Student
System.out.println(studentClass);
// 2.类名.class
Class<Student> studentClass1 = Student.class;
// class com.javase.reflectclassdemo.Student
System.out.println(studentClass1);
// 3.对象.getClass() 获取对象对应类的Class对象
Student student = new Student();
Class<? extends Student> studentClass2 = student.getClass();
// class com.javase.reflectclassdemo.Student
System.out.println(studentClass2);
}
}
总结:
使用反射技术获取构造器对象并使用:
| 方法 | 说明 |
|---|---|
| Constructor>[] getConstructors() | 返回所有构造器对象得数组(只能拿public的)。 |
| Constructor>[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到。 |
| Constructor getConstructor(Class>… parameterTypes) | 返回单个构造器对象(只能拿public的)。 |
| Constructor getDeclaredConstructor(Class>… parameterTypes) | 返回单个构造器对象,存在就能拿到。 |
Student.java
public class Student {
private String name;
private int 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;
}
private Student() {
System.out.println("无参构造器执行!");
}
public Student(String name, int age) {
System.out.println("有参构造器执行!");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
使用反射技术获取构造器对象并使用:
Constructor类中用于创建对象的方法:
| 符号 | 说明 |
|---|---|
| T newInstanc(Object… initargs) | 根据指定的构造器创建对象。 |
| public void setAccessible(boolean flag) | 设置未true,表示取消访问检查,进行暴力反射。 |
Student.java
public class Student {
private String name;
private int 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;
}
private Student() {
System.out.println("无参构造器执行!");
}
public Student(String name, int age) {
System.out.println("有参构造器执行!");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
TestStudent.java
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
public class TestStudent {
/**
* 获取单个构造器
*/
@Test
public void getDeclaredConstructor() throws Exception {
// 1.获取类对象
Class<Student> studentClass = Student.class;
// 2.获取单个的构造器对象 此处为无参构造器
Constructor constructor = studentClass.getDeclaredConstructor();
System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
// 如果遇到了私有的构造器 可以暴力反射 只在本次生效
constructor.setAccessible(true);
// 3.创建Student对象
Student student = (Student) constructor.newInstance();
System.out.println(student);
}
}
总结:
使用反射技术获取成员变量对象并使用:
| 方法 | 说明 |
|---|---|
| Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的)。 |
| Field[] getDeclaredField() | 返回所有成员变量对象的数组,存在就能拿到。 |
| Field getField(String name) | 返回单个成员变量对象(只能拿public的)。 |
| Field getDeclareField(String name) | 返回单个成员变量对象,存在就能拿到。 |
Student.java
public class Student {
private String name;
private int age;
public static String schoolName;
public static final String Country = "中国";
private 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;
}
public static String getSchoolName() {
return schoolName;
}
public static void setSchoolName(String schoolName) {
Student.schoolName = schoolName;
}
public Student() {
System.out.println("无参构造器执行!");
}
public Student(String name, int age) {
System.out.println("有参构造器执行!");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
FieldDemo1.java
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
public class FieldDemo1 {
/**
* 1.获取全部的成员变量
*/
@Test
public void getDeclaredFields() {
// a.定位Class对象
Class<Student> studentClass = Student.class;
// b.定位全部成员变量
Field[] fields = studentClass.getDeclaredFields();
// c.遍历
for (Field field : fields) {
// name==>class java.lang.String
// age==>int
// schoolName==>class java.lang.String
// Country==>class java.lang.String
System.out.println(field.getName() + "==>" + field.getType());
}
}
/**
* 2.获取指定的成员变量
*/
@Test
public void getDeclareField() throws Exception {
// a.定位Class对象
Class<Student> studentClass = Student.class;
// b.根据名称定位某个成员变量
Field field = studentClass.getDeclaredField("age");
// age==>int
System.out.println(field.getName() + "==>" + field.getType());
}
}
使用反射技术获取成员变量对象并使用:
| 符号 | 说明 |
|---|---|
| void set(Object obj, Object value) | 赋值。 |
| Object get(Object obj) | 取值。 |
Student.java
public class Student {
private String name;
private int age;
public static String schoolName;
public static final String Country = "中国";
private 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;
}
public static String getSchoolName() {
return schoolName;
}
public static void setSchoolName(String schoolName) {
Student.schoolName = schoolName;
}
public Student() {
System.out.println("无参构造器执行!");
}
public Student(String name, int age) {
System.out.println("有参构造器执行!");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
FieldDemo2.java
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
public class FieldDemo2 {
@Test
public void setField() throws Exception {
// a.获取类对象
Class<Student> studentClass = Student.class;
// b.提取某个成员变量
Field ageField = studentClass.getDeclaredField("age");
// 暴力打开权限
ageField.setAccessible(true);
// c.赋值
Student student = new Student();
ageField.set(student, 18);
// Student{name='null', age=18}
System.out.println(student);
// d.取值
int age = (int) ageField.get(student);
// 18
System.out.println(age);
}
}
总结:
使用反射技术获取方法对象并使用:
| 方法 | 说明 |
|---|---|
| Method[] getMethods() | 返回所有成员方法对象的数组。(只能拿public的) |
| Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到。 |
| Method getMethod(String name, Class>… parameterTypes) | 返回单个成员方法对象。(只能拿public的) |
| Method getDeclaredMethod(String name, Class>… parameterTypes) | 返回单个成员方法对象,存在就能拿到。 |
使用反射技术获取方法对象并使用:
Method类中用于触发执行的方法:
| 方法 | 说明 |
|---|---|
| Object invoke(Object obj, Object… args) | 运行方法: 参数一:用obj对象调用该方法。 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
Dog.java
public class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dog() {
}
public Dog(String name) {
this.name = name;
}
public void run() {
System.out.println("狗跑的很快!");
}
public void eat() {
System.out.println("狗啃骨头!");
}
public String eat(String name) {
System.out.println("狗吃" + name);
return "吃的很开心!";
}
public static void address() {
System.out.println("灌江口");
}
}
MethodDemo.java
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
public class MethodDemo {
/**
* 1.获取全部方法
*/
@Test
public void getDeclaredMethods() {
// a.获取类对象
Class<Dog> dogClass = Dog.class;
// b.提取全部方法
Method[] methods = dogClass.getDeclaredMethods();
// c.遍历全部方法
for (Method method : methods) {
// getName 返回值类型:class java.lang.String 参数个数:0
// run 返回值类型:void 参数个数:0
// setName 返回值类型:void 参数个数:1
// address 返回值类型:void 参数个数:0
// eat 返回值类型:void 参数个数:0
// eat 返回值类型:class java.lang.String 参数个数:1
System.out.println(method.getName() + " 返回值类型:" + method.getReturnType() + " 参数个数:" + method.getParameterCount());
}
}
@Test
public void getDeclardMethod() throws Exception {
// a.获取类对象
Class<Dog> dogClass = Dog.class;
// b.提取单个方法对象
Method method = dogClass.getMethod("eat");
Method method1 = dogClass.getMethod("eat", String.class);
// 暴力打开权限
method.setAccessible(true);
method1.setAccessible(true);
// c.触发方法的执行
Dog dog = new Dog();
// 注意:方法如果是没有返回结果的,那么返回的是null
// 狗啃骨头!
Object result = method.invoke(dog);
// null
System.out.println(result);
// 狗吃骨头
Object result1 = method1.invoke(dog, "骨头");
// 吃的很开心!
System.out.println(result1);
}
}
总结:
反射的作用-绕过编译阶段为集合添加数据:
反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入任意类型的元素的。
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
// 报错
// list.add("白子画");
list.add(99);
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList,泛型相当于被擦除了。
ReflectDemo.java
import java.lang.reflect.Method;
import java.util.ArrayList;
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 需求: 反射实现泛型擦除后 加入其他类型的元素
ArrayList<String> list = new ArrayList<>();
ArrayList<Integer> list1 = new ArrayList<>();
System.out.println(list.getClass());
System.out.println(list1.getClass());
// ArrayList.class
System.out.println(list.getClass() == list1.getClass());
System.out.println("-----------------");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(9);
list2.add(10);
Class studentClass = list2.getClass();
// 定位studentClass类中的add方法
Method add = studentClass.getDeclaredMethod("add", Object.class);
boolean result = (boolean) add.invoke(list2, "Python");
// true
System.out.println(result);
// [9, 10, Python]
System.out.println(list2);
/* 不用反射突破泛型限制 */
ArrayList list3 = list2;
list3.add("Java");
// [9, 10, Python, Java]
System.out.println(list3);
}
}
总结:
反射做通用框架:
需求:
分析:
Student.java
/**
* 学生类
*/
public class Student {
private String name;
private char sex;
private int age;
private String className;
private String 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;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", className='" + className + '\'' +
", hobby='" + hobby + '\'' +
'}';
}
}
Teacher.java
**
* 老师类
*/
public class Teacher {
private String name;
private char sex;
private double 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;
}
public Teacher() {
}
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", sex=" + sex +
", salary=" + salary +
'}';
}
}
MyUtil.java
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class MyUtil {
/**
* 保存任意类型的对象
* @param object 任意类型的对象
*/
public static void save(Object object) {
try {
// 创建打印流对象 追加写入
PrintStream printStream = new PrintStream(
new FileOutputStream("day17-oop-demo/src/com/javase/reflectframework/data.txt", true)
);
// 1.提取该对象的全部成员变量 只有反射可以解决
Class<?> objectClass = object.getClass();
// 保存类名信息 getSimpleName()获取当前类名 getName()获取全限名
printStream.println("===" + objectClass.getSimpleName() + "===");
// 2.提取它的全部成员变量
Field[] fields = objectClass.getDeclaredFields();
// 3.获取成员变量的信息
for (Field field : fields) {
// 成员变量名称
String variableName = field.getName();
// 取值 提取该成员变量在object对象中的值
field.setAccessible(true);
String variableValue = field.get(object) + "";
// 保存变量名称和变量值
printStream.println(variableName + "=" + variableValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ReflectDemo.java
/**
* 目标:提供一个通用框架 支持保存所有对象的具体信息
*/
public class ReflectDemo {
public static void main(String[] args) {
Student student = new Student();
student.setName("花千骨");
student.setClassName("葵班");
student.setAge(16);
student.setHobby("修仙");
student.setSex('女');
// 保存student对象
MyUtil.save(student);
Teacher teacher = new Teacher();
teacher.setName("朽木清流");
teacher.setSex('男');
teacher.setSalary(10000);
// 保存teacher对象
MyUtil.save(teacher);
}
}
生成的文件:data.txt
===Student===
name=花千骨
sex=女
age=16
className=葵班
hobby=修仙
===Teacher===
name=朽木清流
sex=男
salary=10000.0
总结:
注解概述:
注解的作用是什么呢?
自定义注解(格式):
自定义注解就是自己做一个注解来使用。
public @interface 注解名称 {
public 属性类型 属性名() default 默认值;
}
特殊属性:
MyBook.java
public @interface MyBook {
String name();
String[] authors();
double price();
}
Book.java
public @interface Book {
// 特殊属性
String value();
}
AnnotationDemo.java
/**
* 目标:学会自定义注解 掌握其定义格式和语法
*/
@MyBook(name = "《硅谷之火》", authors = {"迈克尔·斯韦因"}, price = 33.9)
@Book("/add")
public class AnnotationDemo {
@MyBook(name = "《硅谷之火》", authors = {"迈克尔·斯韦因"}, price = 33.9)
private AnnotationDemo() {
}
@MyBook(name = "《硅谷之火》", authors = {"迈克尔·斯韦因"}, price = 33.9)
public static void main(String[] args) {
}
}
元注解:
元注解有两个:
JUnit框架中源码:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(
status = Status.STABLE,
since = "5.0"
)
@Testable
public @interface Test {
}
MyTest.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
* 约束只能用于方法、成员变量
*/
@Target({ElementType.METHOD, ElementType.FIELD})
// 注解一直活着 在运行阶段也不消失
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
AnnotationDemo.java
/**
* 目标:认识元注解
*/
// 此处用该注解会报错
// @MyTest
public class AnnotationDemo {
@MyTest
private String name;
@MyTest
public void test() {
}
@MyTest
public static void main(String[] args) {
}
}
总结:
注解的解析:
与注解解析相关的接口:
Annotation:注解的顶级接口,注解都是Annotation类型的对象。
AnnotatedElement:该接口定义了与注解解析相关的解析方法。
| 方法 | 说明 |
|---|---|
| Annotation[] getDeclaredAnnotations() | 获得当前对象上使用的所有注解,返回注解数组。 |
| T gteDeclaredAnnotation(Class annotationClass) | 根据注解类型获得对应注解对象。 |
| boolean isAnnotationPresent(Class annotationClass) | 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则返回false。 |
所有的类成分:Class、Method、Field,Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力。
解析注释的技巧:
案例:注解解析
需求:
Book.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
// 特殊属性
String value();
double price() default 100;
String[] author();
}
BookStoreTest.java
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 目标:完成注解的解析
*/
public class BookStoreTest {
@Test
public void parseClass() {
// a.先得到类对象
Class<BookStore> bookStoreClass = BookStore.class;
// b.判断这个类上面是否存在这个注解
if (bookStoreClass.isAnnotationPresent(Book.class)) {
// c.直接获取该注释对象
Book book = (Book) bookStoreClass.getDeclaredAnnotation(Book.class);
System.out.println(book.value());
System.out.println(book.price());
System.out.println(Arrays.toString(book.author()));
}
}
@Test
public void parseMethod() throws Exception {
// a.先得到类对象
Class<BookStore> bookStoreClass = BookStore.class;
Method method = bookStoreClass.getDeclaredMethod("test");
// b.判断这个类上面是否存在这个注解
if (method.isAnnotationPresent(Book.class)) {
// c.直接获取该注释对象
Book book = (Book) method.getDeclaredAnnotation(Book.class);
System.out.println(book.value());
System.out.println(book.price());
System.out.println(Arrays.toString(book.author()));
}
}
}
@Book(value = "《一往无前》", price = 78, author = {"范海涛"})
class BookStore {
@Book(value = "《价值》", price = 118, author = {"张磊"})
public void test() {
}
}
案例:模拟jUnit框架
需求:
分析:
MyTest.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
AnnotationDemo.java
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AnnotationDemo {
@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 {
AnnotationDemo annotationDemo = new AnnotationDemo();
// a.获取类对象
Class<AnnotationDemo> annotationDemoClass = AnnotationDemo.class;
// b.提取全部方法
Method[] methods = annotationDemoClass.getDeclaredMethods();
// c.遍历方法
for (Method method : methods) {
// 如果有MyTest注解 启动该方法
if (method.isAnnotationPresent(MyTest.class)) {
// d.启动方法
method.invoke(annotationDemo);
}
}
}
}
执行结果:
===test1===
===test3===
什么是代理?
代理主要干什么,是如何工作的?
如何创建代理对象:
Java中代理的代表类是:java.lang.reflect.Proxy
Proxy提供了一个静态方法,用于为对象产生一个代理对象返回。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
/* 为对象返回一个代理对象 */
// 参数一:定义代理类的类加载器。
// 参数二:代理类要实现的接口列表。
// 参数三:将方法调用分派到的处理程序。(代理对象的核心处理程序)
Java中如何生成代理,并指定代理干什么事?
Skill.java
/**
* 唱歌跳舞技能接口
*/
public interface Skill {
/**
* 唱歌
*/
void sing();
/**
* 跳舞
*/
void jump();
}
Star.java
/**
* 明星类
*/
public class Star implements Skill {
private String name;
public Star(String name) {
this.name = name;
}
/**
* 唱歌
*/
@Override
public void sing() {
System.out.println(name + "开始唱歌,唱得很好!");
}
/**
* 跳舞
*/
@Override
public void jump() {
System.out.println(name + "开始跳舞,跳得很好!");
}
}
StarProxy.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 明星代理对象
*/
public class StarProxy {
/**
* 设计一个方法来返回一个明星对象的代理对象
* @param star 明星对象
* @return 明星代理对象
*/
public static Skill getProxy(Star star) {
// 为明星对象生成一个代理对象
return (Skill) Proxy.newProxyInstance(
star.getClass().getClassLoader(),
star.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("收首付款...");
System.out.println("把明星送出去唱歌跳舞。");
// 让明星唱歌跳舞
Object result = method.invoke(star, objects);
System.out.println("收尾款,把明星接回来。");
return result;
}
}
);
}
}
Test.java
public class Test {
public static void main(String[] args) {
/* 目标:学习开发出一个动态代理的对象出来,理解动态代理的执行流程 */
// 1.创建一个明星类对象 明星类对象必须实现 唱歌跳舞技能接口
Star star = new Star("花千骨");
// 2.为明星对象生成一个明星代理对象
Skill starProxy = StarProxy.getProxy(star);
// 3.执行方法
starProxy.sing();
// starProxy.jump();
}
}
总结:
案例:模拟企业业务功能开发,完成每个功能的性能统计
需求:
分析:
优化代码之前:
UserService.java
/**
* 用户服务接口
*/
public interface UserService {
/**
* 登录
*
* @param username 用户名
* @param password 密码
* @return 是否登录成功
*/
String login(String username, String password);
/**
* 删除用户
*/
void deleteUsers();
/**
* 查询所有用户
* @return 所有用户
*/
String selectUsers();
}
UserServiceImpl.java
/**
* 用户服务类
*/
public class UserServiceImpl implements UserService {
/**
* 登录
*
* @param username 用户名
* @param password 密码
* @return 是否登录成功
*/
@Override
public String login(String username, String password) {
// 开始时间
long startTime = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
String result = "登录名或密码错误!";
if ("admin".equals(username) && "123456".equals(password)) {
result = "登录成功!";
}
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println("login方法耗时:" + (endTime - startTime) / 1000.0 + "秒");
return result;
}
/**
* 删除用户
*/
@Override
public void deleteUsers() {
// 开始时间
long startTime = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println("deleteUsers方法耗时:" + (endTime - startTime) / 1000.0 + "秒");
}
/**
* 查询所有用户
*
* @return 所有用户
*/
@Override
public String selectUsers() {
// 开始时间
long startTime = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println("selectUsers方法耗时:" + (endTime - startTime) / 1000.0 + "秒");
return null;
}
}
Test.java
/**
* 目标:掌握使用动态代理解决问题, 理解使用动态代理的优势
* 用户服务类多个方法都需要统计执行时间, "统计执行时间代码重复", 使用代理来解决,只需要写一次"统计时间代码".
*/
public class Test {
public static void main(String[] args) {
// 创建用户服务对象
UserService userService = new UserServiceImpl();
// 登录
System.out.println(userService.login("admin", "123456"));
// 删除用户
userService.deleteUsers();
// 查询所有用户
userService.selectUsers();
}
}
执行结果:
login方法耗时:1.0秒
登录成功!
deleteUsers方法耗时:1.0秒
selectUsers方法耗时:1.0秒
优化代码:
UserServiceImpl.java
/**
* 用户服务类
*/
public class UserServiceImpl implements UserService {
/**
* 登录
*
* @param username 用户名
* @param password 密码
* @return 是否登录成功
*/
@Override
public String login(String username, String password) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
String result = "登录名或密码错误!";
if ("admin".equals(username) && "123456".equals(password)) {
result = "登录成功!";
}
return result;
}
/**
* 删除用户
*/
@Override
public void deleteUsers() {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询所有用户
*
* @return 所有用户
*/
@Override
public String selectUsers() {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
UserServiceProxy.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 用户服务代理类
*/
public class UserServiceProxy {
/**
* 通过一个静态方法, 为用户业务对象返回一个代理对象
*/
public static UserService getProxy(UserService userService) {
return (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// 开始时间
long startTime = System.currentTimeMillis();
// 真正触发对象的行为执行
Object result = method.invoke(userService, objects);
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + ":" + (endTime - startTime) / 1000.0 + "秒");
return result;
}
}
);
}
}
Test.java
/**
* 目标:掌握使用动态代理解决问题, 理解使用动态代理的优势
* 用户服务类多个方法都需要统计执行时间, "统计执行时间代码重复", 使用代理来解决,只需要写一次"统计时间代码".
*/
public class Test {
public static void main(String[] args) {
// 创建用户服务代理对象
UserService userServiceProxy = UserServiceProxy.getProxy(new UserServiceImpl());
// 登录
System.out.println(userServiceProxy.login("admin", "123456"));
// 删除用户
userServiceProxy.deleteUsers();
// 查询所有用户
userServiceProxy.selectUsers();
}
}
执行结果:
login:1.0秒
登录成功!
deleteUsers:1.001秒
selectUsers:1.001秒
动态代理的优点:
可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用。
简化了编程工作、提高了开发效率,同时提高了软件系统的可扩展性。
可以被代理对象的所有方法做代理。
非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 用户服务代理类
*/
public class UserServiceProxy {
/**
* 通过一个静态方法, 为用户业务对象返回一个代理对象
*/
public static <T> T getProxy(T t) {
return (T) Proxy.newProxyInstance(
t.getClass().getClassLoader(),
t.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// 开始时间
long startTime = System.currentTimeMillis();
// 真正触发对象的行为执行
Object result = method.invoke(t, objects);
// 结束时间
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + ":" + (endTime - startTime) / 1000.0 + "秒");
return result;
}
}
);
}
}