Java

学习内容

单元测试 反射 注解 动态代理
开发好的系统中存在很多的方法,如和对这些方法的正确性进行测试 如何在程序运行时取得到Class对象,然后取获得Class中的每个成分 注解是什么,具体是如何在Java程序中解决问题的? 框架技术的底层会用到的

单元测试

概述

  • 单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法正确性

当前测试方法,存在问题

  • 只有一个main方法,如果一个方法的测试失败了,其他方法测试会受影响
  • 无法得到测试的结果报告,需要程序员自己取观察测试是否成功
  • 无法实现自动化测试

JUnit单元测试框架

  • JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当去学习JUnit编写单元测试
  • 此外,几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,Junit目前最新版本是5
JUnit优点
  • JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法
  • JUnit可以生成全部方法的测试报告
  • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试
JUnit单元测试作用
  • 测试类方法的正确性
总结
  1. JUnit单元测试的实现过程是什么样的
    • 必须导入JUnit框架的jar包
    • 定义的测试方法必须是无参数返回值,且公开的方法
    • 测试方法使用@Test注解标记
  2. 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类中静态方法
  • 源代码阶段

    1. forName(String className)
方法二:Class对象阶段
    1. 类名.class
方法三:Runtime运行时阶段
    1. 对象.getClass()

反射获取构造器对象

使用反射技术获取构造器对象并使用
  • 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取构造器的方法
方法 什么
Constructor<?> getConstructors() 返回所有构造器对象的数组(只拿public的)
Constructor<?> getDeclaredConstructors() 返回所有构造器对象的数组,存在就能拿到
Constructor getConstructor(Class<?>...ParameterTypes) 返回单个构造器对象(只能拿public)
Constructor getDeclaredConstructor(Class<?> ...parameterTypes) 返回单个构造器对象,存在就能拿到
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);

    }
}
总结
  1. 利用反射技术获取构造器对象的方式
    • getDeclaredConstructors()
    • getDeclaredConstructor(Class<?> ...parameterTypes)
  2. 反射得到的构造器可以做什么?
    • 依然是创建对象的
      • 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) 取值
总结
  1. 利用反射技术获取成员变量的方式
    • 获取类中成员变量对象的方法
      • getDeclaredFields()
      • getDeclaredField()
  2. 反射得到成员变量可以做什么
    • 依然是再某个对象中取值和赋值
      • 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对象调用该方法
参数二:调用方法传递的参数(如果没有则不写)
参数三:方法返回值(没有则不写)
总结
  1. 利用反射技术获取成员方法对象的方式
    • 获取类中成员方法对象
      • getDeclaredMethods()
      • getDeclaredMethod(Sting name,Class<?> ... parameterTypes)
  2. 反射得到成员方法可以做什么
    • 依然是在某个对象中触发该方法执行
      • 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);

    }
}
总结
  1. 反射为什么可以给约定了泛型的集合存入其他类型的元素?
    • 编译成Class文件进入运行阶段的时候,泛型会自动解除
    • 反射是作用在运行时的技术,此时已经不存在泛型了

反射的作用- 通验框架的底层原理

总结
  1. 反射的作用
    • 可以在运行时得到一个类的全部成分然后操作。
    • 可以破坏封装性。(很突出)
    • 可以破环泛型约束性。(很突出)
    • 更重要的用途适合做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 annotationClass) 根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class annotationClass) 判断档期啊对象是否使用了指定的注解,如果使用了则返回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)
    //为对象返回一个代理对象
    //参数一:定义代理类的类加载器
    //参数二:代理类要实现的接口列表
    //参数三:将方法调用分派到的处理程序。(代理对象的核心处理程序)
总结
  1. 代理是什么?
    • 一个对象,用来对被代理对象的行为额外做一些辅助工作
  2. 在Java中实现动态代理的步骤是什么样的?
    • 必须存在接口
    • 被代理对象需要实现接口
    • 使用Proxy类提供的方法,创建对象的代理对象
  3. 通过代理对象调用方法,执行流程是什么样的
    • 先走向代理
    • 代理可以为方法额外做一些辅助工作
    • 开发真正触发对象的方法的执行
    • 回到代理中,由代理负责返回结果给方法的调用者

动态代理的优点

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

接口

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;
                    }
                });
    }

}
 posted on 2022-10-14 22:07  yulll  阅读(9)  评论(0编辑  收藏  举报