一、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();//无参,无返回值,所以小括号里不需要带任何东西,在方法左边也不需要变量进行接收.
}
}