今天是刘小爱自学Java的第54天。
感谢你的观看,谢谢你。
话不多说,开始今天的学习:
终于还是要学动态代理了,不管多难最终还是得搞定它。
在学它之前,先学习一种设计模式。
一、装饰设计模式
举一个现实里明星和经纪人的例子:
现有一个明星,emm,就叫洛天依吧。
明星是一种身份,很多人都可以是明星,在Java里面可以将其定义成一个接口。
洛天依具体是指某个人,在Java里面可以将其定义成一个类,同时她的身份就是明星,那么实现明星接口就好了。
1LuoTianYi类
①创建star接口
这是一个明星接口,有三个抽象方法:
唱歌sing(int money)方法,money就是出场费;
跳舞dance(int money)方法,也需要对应的出场费;
休息Sleep()方法。
不同的明星会有不同的歌和舞,所以使用抽象方法表示。
②创建LuoTianYi类
她是一个明星,所以需要实现star接口,并重写其中的方法,说明自己会唱什么歌,会跳什么舞。
好,现在问题来了,有人要请洛天依唱歌跳舞。
我们都知道明星一般都会有自己的经纪人,一般都是由经纪人出面谈合作。
噔噔蹬蹬,刘小爱闪亮登场了,刘小爱是谁?
他是LuoTianYi的经纪人。
2刘小爱类
①创建刘小爱类
类中有一个成员变量Star,构造方法参数为star。
这是什么意思呢?
刘小爱同时是很多明星的经纪人,所以他的参数为star接口,创建该类对象的时候,需要传入star接口的实现类。
找那个明星合作,创建刘小爱对象时说明就好了,这是面向接口编程的核心思想。
②重写Sing()方法
现在有人要谈唱歌合作,那由刘小爱去谈价格,价格不够那不行,价格够了就让对应的明星出场唱歌。
③重写Dance()方法
同样的道理,也是价格谈判,出场费都是1万。
④重写sleep()方法
休息时间,不谈合作。
3测试类
最后一切都设置好了,做一个测试:
①创建刘小爱对象
同时说明此时要找哪位明星谈合作,哦,是LuoTianYi。
②说明合作价格
唱歌一万五,跳舞五千。
③控制台输出
唱歌钱够了,所以LuoTianYi开始唱歌了;
跳舞钱不够,所以没有跳舞。
刘小爱这个类就是LuoTianYi这个类的代理。
调用者找洛天依合作,其实是在和刘小爱在谈,在调用者的眼里,刘小爱就是LuoTianYi。
现在合作谈拢了,由谁去执行?由LuoTianYi去执行。
在IO流中,也有和其相似的情况:
我们使用的是缓冲字符流,但是缓冲流的底层是由字符流来执行的,那么缓冲字符流就是字符流的代理。
它们都对应Java中的一种设计模式,叫装饰设计模式:
装饰者:缓冲字符流、刘小爱就是装饰者
被装饰者:字符流、洛天依就是被装饰者
装饰者将被装饰者的方法增强了
该设计模式其实和Java中的继承很相似:
父类就相当于被装饰者
子类就相当于装饰者
子类重写方法就是在增强父类的方法
只不过该设计模式在代码层面比继承更具有拓展性。
学习了装饰设计模式,接着开始动态代理的学习。
二、动态代理
装饰设计模式和动态代理很相似,它是一种静态代理。
如何理解静态和动态?
静态:代理类是创建了的,比如例子中的刘小爱
动态:代理类是不用创建的
在Java里有一个类叫Proxy,翻译过来就是代理的意思。
用这个类可以动态构建一个代理类对象:
使用newProxyInstance()方法,该方法是一个静态方法,所以用类名直接可以调用。
将该方法拆分记忆:new 创建;Proxy 代理;Instance 实例化;也就是创建代理对象,很好记。
现在我们来仔细分析该方法的三个参数,看源码:
①ClassLoader loader
ClassLoader,类加载器,昨天就接触过。
我们写的类,本质上是.java文件,同时开发工具会自动编译成.class文件,但它们都是存放在硬盘上的。
而类加载器就是将类加载进内存,这样才能够运行。
②Class<?>[] interfaces
interfaces,接口的意思。我个人学Java的一个习惯是先理解这个英文单词是什么意思再去记忆其作用。
并且很多命名规则都是见名知意的。
这个参数就是接口对应的Class对象,什么接口?就是被代理类实现的接口,因为它可以实现很多个接口,所以是一个数组。
③InvocationHandler h
InvocationHandle,翻译过来就是调用处理器。
它是一个接口,我们继续看它的源码:
该接口只有一个方法invoke:
proxy:这个就是代理对象
method:这个也就是代理对象调用的方法(例子中的sing方法、dance方法、sleep方法)
args:这个是方法中的参数
好,以上就是对newProxyInstance()方法的说明,完全弄懂了这个方法,也就弄懂了动态代理。
我们现在将代码补全:
①被代理类的类加载器
被代理类是谁?例子中就是LuoTianYi,首先要获取它对应的Class对象。
ty.getClass():三种获取Class对象之一,ly是LuoTianYi的对象,利用对象ly的getClass方法。
拿到其对应的Class对象后,可以调用getClassLoader()方法获取对应的类加载器。
Java里面的很多方法看名字就能知道它的作用是什么。
所以ty.getClass().getClassLoader()就是获取被代理类LuoTianYi的类加载器.
②被代理类所实现的接口
同样的道理,见名知意:
ty.getClass().getInterface()就是获取被代理类实现的接口对应的Class对象,例子中就是star这个接口。
③调用处理器
这是一个接口,所以使用匿名内部类创建其实现类对象,同时重写接口中的invoke方法。
这块代码的编写,其实也就是例子中刘小爱这个类对star接口中的三个抽象方法的重写。
这是具体的业务逻辑,根据不同的需求编写不同的代码,其它的代码都是基本不变的。
其中method这个参数:
proxy调用sing方法时,method就是sing方法
proxy调用dance方法时,method就是dance方法
根据这个我们可以在其中填上方法的具体业务逻辑
④代理类对象 proxy
代理类LiuXiaoAi我们是没有创建的,所以用的是它的父接口star来接受代理类对象,这是多态。
总结:
谢谢你的观看。
如果可以的话,麻烦帮忙点个赞,谢谢你。