Java中的***
当需要调用一个目标对象执行一个方法做某件事时,这时不方便直接用目标对象,或没有目标对象,则可以通过***对象间接的调用目标对象的方法。
***作用:对目标对象进行控制或功能增强
静态***
静态***:***类是提前创建好的,只要直接通过***对象调用目标对象即可(静态***类似于装饰者模式,不过装饰者模式作用主要在于对 被装饰者的功能增强,而***作用主要在于对目标对象进行控制)
Singer(歌手):***类与目标类共同实现的接口
//***对象需要有目标对象全部的方法,***对象与目标对象要实现共同的接口
public interface Singer {
//唱歌
void sing(String song);
//跳舞
void dance(String danceName);
}
ZhangSan(张三):目标类(被***的类)
//目标类
public class ZhangSan implements Singer {
@Override
public void sing(String song) {
System.out.println("唱:"+song);
}
@Override
public void dance(String danceName) {
System.out.println("跳:"+danceName);
}
}
Agent(经纪人):***对象类
//***对象
public class Agent implements Singer {
private ZhangSan zhangSan;
public Agent(ZhangSan zhangSan) {
this.zhangSan = zhangSan;
}
@Override
public void sing(String song) {
//***对象要做的事情(体现了对目标对象的控制与功能增强):调用目标对象同名方法之前可做一些其他操作, 调用目标对象同名方法, 调用目标对象同名方法之后还再可做一些其他操作
//调用目标对象同名方法之前做一些其他操作
System.out.println("修改歌名");
song="两只老虎";
//调用目标对象同名方法
zhangSan.sing(song);
//调用目标对象同名方法之后还再可做一些其他操作
System.out.println("唱完了");
}
@Override
public void dance(String danceName) {
System.out.println("跳:"+danceName);
}
}
Test:测试运行
public class Test {
public static void main(String[] arg){
ZhangSan zhangSan = new ZhangSan();
Agent agent = new Agent(zhangSan);
agent.sing("怒放的生命");
}
}
动态***
动态***:***类不存在,在代码运行过程中,动态生成的***类,再通过***类对象调用目标对象。
思考:生成***对象有什么要求?
***类应该与目标对象有相同方法—>需要提供***类要实现的接口
使用***是要对目标对象进行控制或功能增强—>需要提供***类要做的事情
在代码运行过程中,动态生成的***类,加载到内存中,并创建***类对象—>需要提供类加载器
分两种情况:
- 有接口,有目标对象,生成***对象
Singer(接口)
//***对象需要有目标对象全部的方法,***对象与目标对象要实现共同的接口
public interface Singer {
//唱歌
void sing(String song);
//跳舞
void dance(String danceName);
}
Zhangsan(目标类)
//目标类
public class ZhangSan implements Singer {
@Override
public void sing(String song) {
System.out.println("唱:"+song);
}
@Override
public void dance(String danceName) {
System.out.println("跳:"+danceName);
}
}
Test(通过Proxy生成***对象,让***对象调用目标对象的方法)
public class Test {
public static void main(String[] arg){
//创建目标对象实例
ZhangSan zhangSan = new ZhangSan();
//通过Proxy生成***对象,让***对象调用目标对象的方法
/*参数说明 loader :类加载器 interfaces :接口类的Class数组,表示需要给***的对象提供一组什么接口,提供接口后,***对象实现该接口,就能调用这组接口中的方法了。 InvocationHandler :指定***对象要做什么事情 singerProxy:生成的***对象 */
Singer singerProxy = (Singer) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Singer.class}, new InvocationHandler() {
//invoke方法,指定***对象的行为,返回执行结果
/* proxy,***后的实例对象。 method,对象被调用方法。 args,调用时的参数。 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标对象的方法之前,如果执行目标对象sing方法,更改参数值。
if(method.getName().equals("sing")){
args[0]="凉凉";
System.out.println("换首凉凉,开始唱");
}
//反射调用目标对象的同名方法
/* 参数object:调用哪个对象的方法 参数parameterValues:调用方法时传递的实参 */
Object invoke = method.invoke(zhangSan, args);
//调用目标对象的方法之后
System.out.println("表演完了");
return invoke;
}
});
//调用***对象方法
singerProxy.sing("怒放的生命");
}
}
- 有接口,没有目标对象,生成***对象
Singer(接口)
//***对象需要有目标对象全部的方法,***对象与目标对象要实现共同的接口
public interface Singer {
//唱歌
void sing(String song);
//跳舞
void dance(String danceName);
}
Test(通过Proxy生成***对象,由***对象完成所有工作)
public class Test {
public static void main(String[] arg){
//通过Proxy生成***对象,由***对象完成所有工作
/*参数说明 loader :类加载器 interfaces :接口类的Class数组,表示需要给***的对象提供一组什么接口,提供接口后,***对象实现该接口,就能调用这组接口中的方法了。 InvocationHandler :指定***对象要做什么事情 singerProxy:生成的***对象 */
Singer singerProxy = (Singer) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Singer.class}, new InvocationHandler() {
//invoke方法,指定***对象的行为,返回执行结果
/* proxy,***后的实例对象。 method,对象被调用方法。 args,调用时的参数。 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标对象的方法之前,如果执行目标对象sing方法,更改参数值。
if(method.getName().equals("sing")){
System.out.println("唱:"+args[0]);
}else if (method.getName().equals("dance")){
System.out.println("跳:"+args[0]);
}
return null;
}
});
//调用***对象方法
singerProxy.sing("怒放的生命");
singerProxy.dance("卡路里");
}
}