动态代理(黑马笔记)



一、BigStar 大明星类

java 复制代码
package com.itheima.mydynamicproxy1;
public class BigStar implements Star {
    //实现接口要重写里边的抽象方法
    private String name;
    public BigStar() {}
    public BigStar(String name) {
        this.name = name;
    }
    //唱歌
    @Override  //表示重写接口中的方法
    public String sing(String name){
        System.out.println(this.name + "正在唱" + name);
        return "谢谢";
    }
    //跳舞
    @Override
    public void dance(){
        System.out.println(this.name + "正在跳舞");
        /**
         * 在Java代码中,this关键字用于指代当前对象实例。因此this.name指的是当前BigStar类实例的name属性。
         * 当一个方法内部引用了与参数同名的成员变量时,使用this关键字可以明确地区分它们,
         * 表明你正在访问的是属于当前对象的成员变量name,而不是传递给方法的局部变量name。
         * 所以,表达式(this.name + "正在唱" + name)的意思:
         * 是将当前BigStar对象的name属性值与字符串"正在唱"以及传递给sing方法的参数name(即歌曲名)拼接起来,
         * 形成一个完整的句子,例如如果BigStar对象的name是"小明",调用sing("月亮代表我的心")时,
         * 输出将会是"小明正在唱月亮代表我的心"。
         */
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    public String toString() {
        return "BigStar{name = " + name + "}";
    }
}

二、Star接口,代理类和大明星类都要实现这个接口以获取代理的方法。

java 复制代码
package com.itheima.mydynamicproxy1;
public interface Star {
    //我们可以把所有想要被代理的方法定义在接口当中
    //唱歌,因为在接口里都是抽象方法,所以方法体去掉,前面加abstra
    public abstract String sing(String name);
    //跳舞
    public abstract void dance();
}

三、 ProxyUtil 代理类

java 复制代码
package com.itheima.mydynamicproxy1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
 * 类的作用:创建一个代理
 * */
public class ProxyUtil {
    /*
     * 方法的作用:给一个明星的对象,创建一个代理
     *  形参:被代理的明星对象
     *  返回值:给明星创建的代理

     * 在外界获取代理对象后,方法的调用是怎么样的 需求:
     *   外面的人想要大明星唱一首歌
     *   1. 获取代理的对象
     *      代理对象 = ProxyUtil.createProxy(大明星的对象);
     *   2. 再调用代理的唱歌方法
     *      代理对象.唱歌的方法("只因你太美");
     * */
    //首先要把明星的对象作为参数传过来,我才能给它创建代理
    //方法的返回值,就是我们创建的代理,
    // 所以这里类型可以写Star,因为代理ProxyUtil类 也是要实现Star这个接口的,
    // 所以在这直接写接口的类型是ok的.
    public static Star createProxy(BigStar bigStar) {
       /* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
      public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        参数一:用于指定用哪个类加载器,去加载生成的代理类
        参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法,
        参数三:用来指定生成的代理对象要干什么事情*
        方法体用到了上述方法 */
        Star star = (Star) Proxy.newProxyInstance(//创建出来的是代理对象,看原方法中返回类型是Object的,但是在左边用Star来接收,所以要强转一下
                ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类
                // (相当于找到是谁把当前类的字节码文件加载到内存的,找到这个类加载器后,让它再去加载当前的代理到内存当中)

                new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法,
                //代码中是以数组的方式来体现的,数组中的参数都是字节码,(把接口的字节码放在数组当中)
                // new Class[]{Star.class},表示生成的代理中介,它可以代理Star这个接口里所有的方法,说白了能代理的方法都在接口当中.
                //如果接口有多个,可以把它们都写在数组当中new Class[]{Star.class,A.class,B.class}

                //参数三:用来指定生成的代理对象要干什么事情,通过实现InvocationHandler接口来实现,
                // 因为代理对象要实现Star接口,所以这里要实现InvocationHandler接口,
                //InvocationHandler是接口,因此这里要写一个InvocationHandler实现类的对象,这里用匿名内部类来做,
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                         * 参数一:代理的对象
                         * 参数二:要运行的方法 sing
                         * 参数三:调用sing方法时,传递的实参,因为invoke方法就是代理要干的事情
                         */
                        if ("sing".equals(method.getName())) {
                            System.out.println("准备话筒,收钱");
                        } else if ("dance".equals(method.getName())) {
                            System.out.println("准备场地,收钱");
                        }
                        //去找大明星开始唱歌或者跳舞
                        //代码的表现形式:调用大明星里面唱歌或者跳舞的方法
                        return method.invoke(bigStar, args);//反射的反射机制,通过反射调用bigStar里面的方法,这里的args是"只因你太美"
                        //在调用方法时,如果有参数,要将参数传递过去.
                        //如果方法有返回值,可以将它的运行结果进行返回
                    }
                }
        );
        return star;//返回生成的代理
    }
}

//什么是类加载器? (就是Java在运行时,需要有一个人将那个字节码文件加载到内存中,就是类加载器去加载的)
// 类加载器:负责把一个类的字节码加载到内存中,并且生成一个Class对象.
/*
 * 1. 获取类加载器
 *   1.1 获取系统类加载器
 *       ClassLoader cl = ClassLoader.getSystemClassLoader();
 *   1.2 获取系统类加载器的父类加载器
 *       ClassLoader cl = ClassLoader.getSystemClassLoader().getParent();
 *   1.3 获取扩展类加载器
 *       ClassLoader cl = ClassLoader.getSystemClassLoader().getParent().getParent();
 *   1.4 获取应用程序类加载器
 *       ClassLoader cl = ClassLoader.getSystemClassLoader().getParent().getParent().getParent();
 */

四、测试类

java 复制代码
package com.itheima.mydynamicproxy1;

public class Test {
    public static void main(String[] args) {
    /*
        需求:
            外面的人想要大明星唱一首歌
             1. 获取代理的对象
                代理对象 = ProxyUtil.createProxy(大明星的对象);
             2. 再调用代理的唱歌方法
                代理对象.唱歌的方法("只因你太美");
     */

        //1. 获取代理的对象 proxy
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);//Ctrl+alt+v  自动生成左边
        //2. 调用唱歌的方法
        String result = proxy.sing("只因你太美");
        System.out.println(result);//给谢谢返回值做打印
        //3. 调用跳舞的方法
        proxy.dance();//无参,无返回值,所以小括号里不需要带任何东西,在方法左边也不需要变量进行接收.
    }
}
相关推荐
lsx2024064 分钟前
SQL SELECT 语句:基础与进阶应用
开发语言
小二·6 分钟前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic29 分钟前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it30 分钟前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
懒洋洋大魔王30 分钟前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康35 分钟前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神1 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
宅小海1 小时前
scala String
大数据·开发语言·scala
qq_327342731 小时前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala