Java
学习内容
单元测试 | 反射 | 注解 | 动态代理 |
---|---|---|---|
开发好的系统中存在很多的方法,如和对这些方法的正确性进行测试 | 如何在程序运行时取得到Class对象,然后取获得Class中的每个成分 | 注解是什么,具体是如何在Java程序中解决问题的? | 框架技术的底层会用到的 |
单元测试
概述
- 单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法正确性
当前测试方法,存在问题
- 只有一个main方法,如果一个方法的测试失败了,其他方法测试会受影响
- 无法得到测试的结果报告,需要程序员自己取观察测试是否成功
- 无法实现自动化测试
JUnit单元测试框架
- JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当去学习JUnit编写单元测试
- 此外,几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,Junit目前最新版本是5
JUnit优点
- JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法
- JUnit可以生成全部方法的测试报告
- 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试
JUnit单元测试作用
- 测试类方法的正确性
总结
- JUnit单元测试的实现过程是什么样的
- 必须导入JUnit框架的jar包
- 定义的测试方法必须是无参数返回值,且公开的方法
- 测试方法使用@Test注解标记
- JUnit测试某个方法,测试全部方法怎么处理?成功的标志是什么
- 测试莫格方法直接右键该方法启动测试
- 测试全部方法,可以选择类或者模块启动
- 红色失败,绿色通过
JUnit常用注解(JUnit 4.xxx版本)
注解 | 说明 |
---|---|
@Test | 测试方法 |
@Bfore | 用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次 |
@After | 用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次 |
@BeforeClass | 用来静态修饰方法,该方法会在所有测试方法之前只执行一次 |
@AfterClass | 用来静态修饰方法,该方法会在所有测试方法之后只执行一次 |
- 开始执行的方法:初始化资源
- 执行完之后的方法:释放资源
JUnit常用注解(JUnit 5.xxx版本)
注解 | 说明 |
---|---|
@Test | 测试方法 |
@BforeEach | 用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次 |
@AfterEach | 用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次 |
@BeforeAll | 用来静态修饰方法,该方法会在所有测试方法之前只执行一次 |
@AfterAll | 用来静态修饰方法,该方法会在所有测试方法之后只执行一次 |
- 开始执行的方法:初始化资源
- 执行完之后的方法:释放资源
反射
概述
- 反射是对于任何一个Class类,在“运行的时候”都可以直接得到这个类的全部成分
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量:Field
- 在运行时,可以直接得到这个类的成员方法对象:Method
- 这种运动时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
反射的关键:
-
反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分
HelloWorld.java->javac->HelloWorld.Class Class c = HelloWorld.class
总结
- 反射的基本作用、关键?
- 反射是在运行是获取类的字节码文件对象:然后可以解析类中的全部成分
- 反射的核心思想和关键就:得到编译以后的class文件对象
反射获取类对象
反射第一步:获取Class类的对象
方法一:Class类中静态方法
-
源代码阶段
-
- forName(String className)
方法二:Class对象阶段
-
- 类名.class
方法三:Runtime运行时阶段
-
- 对象.getClass()
反射获取构造器对象
使用反射技术获取构造器对象并使用
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取构造器的方法
方法 | 什么 |
---|---|
Constructor<?> getConstructors() | 返回所有构造器对象的数组(只拿public的) |
Constructor<?> getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor |
返回单个构造器对象(只能拿public) |
Constructor |
返回单个构造器对象,存在就能拿到 |
package com.yu.Day1013Demo.Constructor;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class TestStudent {
//1.getConstructor
@Test
public void getConstructors(){
//a.第一步,获取类对象
Class c = Student.class;
//b.获取类中的全部的构造器对象
Constructor[] constructors = c.getConstructors();
//c.遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"-->"+constructor.getParameterCount());
}
}
//2.getDeclaredConstructors()
@Test
public void getDeclaredConstructors(){
//a.第一步,获取类对象
Class c = Student.class;
//b.获取类中的全部的构造器对象
Constructor[] constructors = c.getDeclaredConstructors();
//c.遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"-->"+constructor.getParameterCount());
}
}
//3.getConstructor(Class...paramenterTypes)
@Test
public void getConstructor() throws Exception {
//a.第一步,获取类对象
Class c = Student.class;
//b.获取类中的全部的构造器对象(按照参数定位无参数构造器)
Constructor constructor = c.getConstructor(String.class,int.class);
//c.输出
System.out.println(constructor.getName()+"-->"+constructor.getParameterCount());
}
//4.getDeclaredConstructor(Class...paramenterTypes)
@Test
public void getDeclaredConstructor() throws Exception {
//a.第一步,获取类对象
Class c = Student.class;
//b.获取类中的全部的构造器对象(按照参数定位无参数构造器)
Constructor constructor = c.getConstructor();
//c.输出
System.out.println(constructor.getName()+"-->"+constructor.getParameterCount());
}
}
package com.yu.Day1013Demo.Constructor;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
private Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Constructor类中用于创建对象的方法
方法 | 说明 |
---|---|
T newInstance(Object... initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 设置true,表示取消访问检查,进行暴力反射 |
package com.yu.Day1013Demo.Constructor;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class TestStudent01 {
//a.第一步获取类对象
@Test
public void getDeclaredConstructor() throws Exception {
//a.第一步,获取类对象
Class c = Student.class;
//b.获取类中的全部的构造器对象(按照参数定位无参数构造器)
Constructor constructor = c.getDeclaredConstructor();
//c.输出
System.out.println(constructor.getName()+"-->"+constructor.getParameterCount());
//如果遇到了私有构造器,可以暴力反射
constructor.setAccessible(true);
//无参构造器
Student s = (Student)constructor.newInstance();
System.out.println(s);
//有参构造器
Constructor cons1 = c.getDeclaredConstructor(String.class,int.class);
System.out.println(cons1.getName()+"-->"+cons1.getParameterCount());
Student s1 = (Student)cons1.newInstance("孙悟空",1000);
System.out.println(s1);
}
}
总结
- 利用反射技术获取构造器对象的方式
- getDeclaredConstructors()
- getDeclaredConstructor(Class<?> ...parameterTypes)
- 反射得到的构造器可以做什么?
- 依然是创建对象的
- public newInstance(Object...initargs)
- 如果是分public的构造器,需要打开权限(暴力反射),然后再创建对象
- setAccessible(boolean)
- 反射可以破环封装性,私有的也可以执行了
- 依然是创建对象的
反射获取成员变量对象
使用反射技术获取成员变量对象并使用
- 反射第一步先得到类对象,然后从类对象中获取类的成分对象
- Class类中用于获取成员变量的方法
方法 | 说明 |
---|---|
Field[] getFields() | 返回所有成员变量对象的数组(只拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclareField(String name) | 返回单个成员变量对象,存在就能拿到 |
- 获取成员变量的作用依然是再某个对象中取值、赋值
Field类中用于取值、赋值的方法
方法 | |
---|---|
void set(Object obj,Object value) | 赋值 |
Object get(Object obj) | 取值 |
总结
- 利用反射技术获取成员变量的方式
- 获取类中成员变量对象的方法
- getDeclaredFields()
- getDeclaredField()
- 获取类中成员变量对象的方法
- 反射得到成员变量可以做什么
- 依然是再某个对象中取值和赋值
- void set(Object obj,Object value)
- Objcet get(Object obj)
- 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
- setAccessible(boolean)
- 依然是再某个对象中取值和赋值
package com.yu.Day1013Demo.Field.Constructor;
public class Student {
private String name;
private int age;
public static String schoolName;
public static final String COUNTTER = "中国";
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.yu.Day1013Demo.Field.Constructor;
import org.junit.Test;
import java.lang.reflect.Field;
public class FieldDemo01 {
@Test
public void getDeclaredFields(){
//a.定位Class对象
Class c = Student.class;
//b. 定位全部成员变量
Field[] fields = c.getDeclaredFields();
//c.变量输出
for (Field field : fields) {
System.out.println(field.getName()+"--->"+field.getType());
}
}
@Test
public void getDeclaredField() throws Exception{
//a.定位Class对象
Class c = Student.class;
//b. 定位全部成员变量
Field f = c.getDeclaredField("age");
//c.变量输出
System.out.println(f.getName()+"--->"+f.getType());
}
}
package com.yu.Day1013Demo.Field.Constructor;
import org.junit.Test;
import java.lang.reflect.Field;
public class FieldDemo02 {
@Test
public void setField() throws Exception{
Class c = Student.class;
Field f = c.getDeclaredField("age");
Student s = new Student();
f.setAccessible(true);
f.set(s,18);;
System.out.println(s);
}
}
反射获取方法对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
- Class类中用于获取成员方法的方法
方法 | 说明 |
---|---|
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name,Class<?>...parameterTypes) | 返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name,Class<?>...parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
Method类中用于触发执行的方法
方法 | 说明 |
---|---|
Object invoke(Object obj,Objcet...args) | 运行方法 参数一:用obj对象调用该方法 参数二:调用方法传递的参数(如果没有则不写) 参数三:方法返回值(没有则不写) |
总结
- 利用反射技术获取成员方法对象的方式
- 获取类中成员方法对象
- getDeclaredMethods()
- getDeclaredMethod(Sting name,Class<?> ... parameterTypes)
- 获取类中成员方法对象
- 反射得到成员方法可以做什么
- 依然是在某个对象中触发该方法执行
- Object invoke(Object obj,Objcet..args)
- 如果某成员方法是非public的,需要权限(暴力反射),然后再触发执行
- setAccessible(boolean)
- 依然是在某个对象中触发该方法执行
package com.yu.Day1013Demo.method;
public class Dog {
private String name;
public Dog(){
}
public Dog(String name) {
this.name = name;
}
private void eat(){
System.out.println("狗吃骨头");
}
private String eat(String name){
System.out.println("狗吃"+name);
return "吃的很开心";
}
public static void inAddr(){
System.out.println("在黑马学习java");
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
package com.yu.Day1013Demo.method;
import org.junit.Test;
import java.lang.reflect.Method;
public class MethodDemo01 {
//获取全方法
@Test
public void getDeclaredMethods(){
Class c = Dog.class;
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName()+"返回值类型"+method.getReturnType()+"参数个数"+method.getParameterCount());
}
}
//获取某一个方法
@Test
public void getDeclaredMethod() throws Exception{
Class c = Dog.class;
Method method = c.getDeclaredMethod("eat");
Method method2 = c.getDeclaredMethod("eat",String.class);
method.setAccessible(true);
method2.setAccessible(true);
Dog d = new Dog();
//不带参数
Object result = method.invoke(d);
System.out.println(result);
//带参数
Object resulf2 = method2.invoke(d,"骨头");
System.out.println(resulf2);
}
}
反射作用-绕过编译阶段为集合添加数据
- 反射的作用在运行是的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他类型的元素的
ArrayList<Integet> list = new ArrayList<>();
list.add(100);
//list.add("黑马");//报错
list.add(99);
- 泛型只是在编译阶段可以约束集合只能操作魔种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
package com.yu.Day1013Demo.genericity;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class ReflectDemo {
public static void main(String[] args) throws Exception{
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list1.getClass()==list2.getClass());
System.out.println("--------------------------------");
list2.add(222);
list2.add(111);
//llist2.add("黑马");
Class c = list2.getClass();
//定位c类中的add方法
Method add = c.getDeclaredMethod("add",Object.class);
boolean rs = (boolean)add.invoke(list2,"黑啊吗");
System.out.println(rs);
System.out.println(list2);
}
}
总结
- 反射为什么可以给约定了泛型的集合存入其他类型的元素?
- 编译成Class文件进入运行阶段的时候,泛型会自动解除
- 反射是作用在运行时的技术,此时已经不存在泛型了
反射的作用- 通验框架的底层原理
总结
- 反射的作用
- 可以在运行时得到一个类的全部成分然后操作。
- 可以破坏封装性。(很突出)
- 可以破环泛型约束性。(很突出)
- 更重要的用途适合做Java高级框架
package com.yu.Day1013Demo.framework;
public class Student {
private String name;
private char sex;
private int age;
private String className;
private String hobby;
public Student(){}
public Student(String name, char sex, int age, String className, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.className = className;
this.hobby = hobby;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
package com.yu.Day1013Demo.framework;
public class Teacher {
private String name;
private char sex;
private double salary;
public Teacher() {
}
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.yu.Day1013Demo.framework;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class MybatisUtil {
/**
* 保存任意类型的对象
* @param obj
*/
public static void save(Object obj){
try (
PrintStream ps = new PrintStream(new FileOutputStream("src//datast.txt",true));
){
//1.提取这个第项的全部成员便,只有反射可以解决
Class c = obj.getClass();
// c.getSimpleName()获取当前类名 c.getName获取全限名 包名加类名
ps.println("========"+c.getSimpleName()+"===========");
//2. 提取全部成员变量
Field[] fields = c.getDeclaredFields();
//3.获取成员变量信息
for (Field field : fields) {
String name = field.getName();
//提取本成员变量在obj对象中的值(取值)
field.setAccessible(true);
String value = field.get(obj)+"";
ps.println(name+"="+value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.yu.Day1013Demo.framework;
public class ReflectDemo {
public static void main(String[] args) throws Exception{
Student s = new Student("yu",'男',18,"qlit","chi,wan");
MybatisUtil.save(s);
Teacher t = new Teacher("yu",'男',10010);
MybatisUtil.save(t);
}
}
注解
概述
- Java注解(Annotation)又称Java标注,是JDK5.0引入的一种注释机制
- Java语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注
作用
- 对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定
自定义注解
格式
-
自定义注解就是自己做一个注解来使用
-
public @interface 注解名称{ public 属性类型 属性名() default 默认值;
Java支持的数据类型基本上都支持
特殊属性
- value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写
- 但是如果有多个属性,且多个属性没有默认值,那么value名称不能省略的
package com.yu.Day1013Demo.d8_annotation;
public @interface Book {
String value();//可直接写value值
int age() default 99;
}
元注解
- 就是注解注解的注解
元注解有两个
- @Target:约束自定义注解只能在哪些地方使用
- @Retention:申明注解的生命周期
@Target中可以使用的值定义在ElementType枚举类中,常用值如下
- TYPE 类,接口
- FIELD 成员变量
- METHOD 成员方法
- PARAMETER 方法参数
- CONSTRUCTOR 构造器
- LOCAL_VARIABLE 局部变量
@Retention中可以使用的值定义在RetentionPolicy枚举类中,常用值如下
- SOURCE 注解只作用在源代码阶段,生成的字节码文件中不存在
- CLASS 注解作用在源代码阶段,字节码文件阶段,运行阶段不存在,默认值
- RUNTIME 注解作用在源代码阶段,字节码文件阶段,运行阶段(开发常用)
注解的解析
- 注解的操作中进场需要进行解析,注解的注解就是判断是否存在注解,存在注解就解析出内容
与注解解析相关的接口
- Annotation:注解的顶级接口,注解都是Annotation类型的对象
- AnnotatedElement:该接口定义了与注解解析相关的解析方法
方法 | 说明 |
---|---|
Annotation[] getDeclaredAnnotations() | 获得当前对象上使用的所有注解,发货注解数组 |
T getDeclaredAnnotation(Class |
根据注解类型获得对应注解对象 |
boolean isAnnotationPresent(Class |
判断档期啊对象是否使用了指定的注解,如果使用了则返回true,否则返回false |
- 所有的类成分Class,Method,Field,Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力
解析注解的技巧
- 注解在哪个成分上,我们就先拿哪个成分对象
- 比如注解作用在成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
- 比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
- 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解
package com.yu.Day1013Demo.d8_annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Bookk {
String value();
double price() default 100;
String[] authors();
}
package com.yu.Day1013Demo.d8_annotation;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
public class AnnotationDemo02 {
@Test
public void parseClass(){
Class c = BookStore.class;
if(c.isAnnotationPresent(Bookk.class)){
Bookk book = (Bookk)c.getDeclaredAnnotation(Bookk.class);
System.out.println(book.value());
System.out.println(Arrays.toString(book.authors()));
System.out.println(book.price());
}
}
@Test
public void parseMethod() throws NoSuchMethodException {
Class c = BookStore.class;
Method m = c.getDeclaredMethod("test");
if(m.isAnnotationPresent(Bookk.class)){
Bookk book = (Bookk)m.getDeclaredAnnotation(Bookk.class);
System.out.println(book.value());
System.out.println(Arrays.toString(book.authors()));
System.out.println(book.price());
}
}
}
@Bookk(value = "情深深雨蒙蒙",price = 99.9,authors = {"琼瑶","dlei"})
class BookStore{
@Bookk(value = "三少爷的🗡",authors = {"yu","2222"})
public void test(){}
}
注解的应用:JUnit
package com.yu.Day1013Demo.d8_annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MyTest {
}
package com.yu.Day1013Demo.d8_annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AnnotationDemo03 {
@MyTest
public void test1(){
System.out.println("1111");
}
@MyTest
public void test2(){
System.out.println("2222");
}
public void test3(){
System.out.println("33333");
}
public static void main(String[] args) throws Exception, IllegalAccessException {
AnnotationDemo03 t = new AnnotationDemo03();
Class c = AnnotationDemo03.class;
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
if(method.isAnnotationPresent(MyTest.class)){
method.invoke(t);
}
}
}
}
动态代理
概述
代理主要是对对象的行为额外做一些辅助操作
如何创建代理对象
- Java中代理的代表类是:java.lang.reflect.Proxy
- Proxy提供了一个静态方法,用于为对象产生一个代理对象返回
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
//为对象返回一个代理对象
//参数一:定义代理类的类加载器
//参数二:代理类要实现的接口列表
//参数三:将方法调用分派到的处理程序。(代理对象的核心处理程序)
总结
- 代理是什么?
- 一个对象,用来对被代理对象的行为额外做一些辅助工作
- 在Java中实现动态代理的步骤是什么样的?
- 必须存在接口
- 被代理对象需要实现接口
- 使用Proxy类提供的方法,创建对象的代理对象
- 通过代理对象调用方法,执行流程是什么样的
- 先走向代理
- 代理可以为方法额外做一些辅助工作
- 开发真正触发对象的方法的执行
- 回到代理中,由代理负责返回结果给方法的调用者
动态代理的优点
- 可以在不改变方法源码的情况下,实现对方法给你的增强,提高代码的复用
- 简化编程工作,提高了开发效率,同时提高了软件系统的可扩展性
- 可以为被代理对象的所有方法做代理
- 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为本身做代理
接口
package com.yu.Day1013Demo.d9Demo;
public interface Skll {
void jump();
void sing();
}
对象
package com.yu.Day1013Demo.d9Demo;
public class Star implements Skll {
private String name;
public Star(String name){
this.name = name;
}
@Override
public void jump() {
System.out.println(name+"正在跳舞!!!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void sing() {
System.out.println(name+"正在唱歌!!!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试类
package com.yu.Day1013Demo.d9Demo;
public class Demo01 {
public static void main(String[] args) {
Star s = new Star("🐏");
// Skll s2 = StarAgentProxy.getProxy(s);
Skll s2 = SKLLLLL.getStart(s);
s2.jump();
s2.sing();
}
}
代理类
package com.yu.Day1013Demo.d9Demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SKLLLLL {
public static <T> T getStart(T obj){
return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long StartTime = System.currentTimeMillis();
Object re = method.invoke(obj,args);
long endTimes = System.currentTimeMillis();
System.out.println("方法名称:"+method.getName()+"方法耗时:"+(endTimes-StartTime)/1000.0+"S");
return re;
}
});
}
}