一、BigStar 大明星类
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 "谢谢";}//跳舞@Overridepublic 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接口,代理类和大明星类都要实现这个接口以获取代理的方法。
package com.itheima.mydynamicproxy1;
public interface Star {//我们可以把所有想要被代理的方法定义在接口当中//唱歌,因为在接口里都是抽象方法,所以方法体去掉,前面加abstrapublic abstract String sing(String name);//跳舞public abstract void dance();
}
三、 ProxyUtil 代理类
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() {@Overridepublic 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();*/
四、测试类
package com.itheima.mydynamicproxy1;public class Test {public static void main(String[] args) {/*需求:外面的人想要大明星唱一首歌1. 获取代理的对象代理对象 = ProxyUtil.createProxy(大明星的对象);2. 再调用代理的唱歌方法代理对象.唱歌的方法("只因你太美");*///1. 获取代理的对象 proxyBigStar bigStar = new BigStar("鸡哥");Star proxy = ProxyUtil.createProxy(bigStar);//Ctrl+alt+v 自动生成左边//2. 调用唱歌的方法String result = proxy.sing("只因你太美");System.out.println(result);//给谢谢返回值做打印//3. 调用跳舞的方法proxy.dance();//无参,无返回值,所以小括号里不需要带任何东西,在方法左边也不需要变量进行接收.}
}