委托类分析——委托类:Interface by 委托实现类;委托类(属性:委托实现类):Interface by 属性
最近再学习委托的时候有些绕,做个笔记分享一下吧,顺便把kotlin的属性,字段,主从构造还有委托的实现一起从编译后的java代码分析下属性就是带val、var修饰的字段如何理解呢?看下面val,var的分析这次先分析委托类的java代码实现,后续文章在分析委托属性的set/get方法如何进行委托已经编译后的Java代码分析(看了委托的基本原来和实现思路之后相信属性的委托更能看懂)都说组合优于继承,
前言
最近再学习委托的时候有些绕,做个笔记分享一下吧,顺便把kotlin的属性,字段,主从构造还有委托的实现一起从编译后的java代码分析下
属性就是带val、var修饰的字段如何理解呢?看下面val,var的分析
这次先分析委托类的java代码实现,后续文章在分析委托属性的set/get方法如何进行委托已经编译后的Java代码分析(看了委托的基本原来和实现思路之后相信属性的委托更能看懂)
都说组合优于继承,但是java并没有在语音层面直接提供委托的写法,kotlin不一样,语言本身就支持委托。
看完这篇文章你会收获:
1、val,var修饰的字段和普通字段区别
2、委托的基本用法及实现原理
3、kotlin中常见的内置委托
几个源文件
普通委托类:
class DelegateClass : IDelegate by DelegateImplClass()
属性委托类:
class DelegateClassByProperty(var delegateClass: DelegateImplClass) : IDelegate by delegateClass
委托接口:
interface IDelegate {
fun eat()
fun sleep(){
println("")
}
companion object A{
fun work(){
println("work")
}
}
}
委托实现类:
class DelegateImplClass :IDelegate{
override fun eat() {
println("DelegateImplClass eat")
}
override fun sleep() {
println("DelegateImplClass sleep")
}
}
val,var
修饰符:
如果只是在函数中声明了一个变量并没有添加val或者var关键词进行修饰,那么他本身就是一个参数传入到方法中
Code:
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty {
public DelegateClassByProperty(@NotNull DelegateClass delegate2) {
Intrinsics.checkNotNullParameter(delegate2, "delegate2");
super();
}
}
-----------------------------------《End》---------------------------------------------
但是如果修饰了,就会在类内部声明一个全局变量。val变量修饰的话添加get方法返回这个全局变量由于不可变因此没有set方法;对于var修饰符,也会在类内部声明一个全局变量并添加set/get方法
由于有了set/get方法,这个全局变量也可以叫做类的属性
val code:
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty {
//编译器自动添加的全局变量
@NotNull
private final DelegateClass delegate2;
@NotNull
public final DelegateClass getDelegate2() {
return this.delegate2;
}
public DelegateClassByProperty(@NotNull DelegateClass delegate2) {
Intrinsics.checkNotNullParameter(delegate2, "delegate2");
super();
this.delegate2 = delegate2;
}
}
-----------------------------------《End》---------------------------------------------
var code:
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty {
@NotNull
private DelegateClass delegate2;
@NotNull
public final DelegateClass getDelegate2() {
return this.delegate2;
}
public final void setDelegate2(@NotNull DelegateClass var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.delegate2 = var1;
}
public DelegateClassByProperty(@NotNull DelegateClass delegate2) {
Intrinsics.checkNotNullParameter(delegate2, "delegate2");
super();
this.delegate2 = delegate2;
}
}
-----------------------------------《End》---------------------------------------------
主从构造函数:
只有主构造函数可以声明带有val,var修饰符的参数,为什么从构造函数不可以呢?从构造函数应该是为主构造函数服务的,从构造只需使用主构造声明的变量即可,否则主从都声明变量会带来混乱
关于Delegate:
kotlin编译器会在编译期间为维托的实现类自动声明一个隐式的实例,编译器自动为委托类添加需要的方法实现并路由到这个隐式声明的实例中
code:
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty implements IDelegate {
// $FF: synthetic field
//编译器自动添加的隐式实例,编译器自动添加需要实现的方法并路由到隐式实例中
private final DelegateImplClass $$delegate_0 = new DelegateImplClass();
public void eat() {
this.$$delegate_0.eat();
}
public void sleep() {
this.$$delegate_0.sleep();
}
}
-----------------------------------《End》---------------------------------------------
最简单的声明就是直接在by后面跟上委托的实现类,但是限制了灵活性其实现只能是固定的某个类,因此出现了可以委托给构造函数传入的参数(注意是参数不是属性)
code:
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty implements IDelegate {
// $FF: synthetic field自动生成的字段
private final DelegateImplClass $$delegate_0;
public DelegateClassByProperty(@NotNull DelegateImplClass delegateClass) {
Intrinsics.checkNotNullParameter(delegateClass, "delegateClass");
super();
//还是需要声明代理实例,只不过不是直接赋值而是在构造函数中将参数的值赋值给这个实例
this.$$delegate_0 = delegateClass;
}
public void eat() {
this.$$delegate_0.eat();
}
public void sleep() {
this.$$delegate_0.sleep();
}
}
-----------------------------------《End》---------------------------------------------
如果构造函数没有声明val/var,和直接委托一样也是会在类内部声明一个全局的变量在构造函数中赋值为这个参数,之后的委托实现路由到这个全局变量中
val和Delegate的冲突
上面说过val和var会在类的内部声明一个全局变量,而Delegate也会委托给类内部自己单独声明的委托实例中
对于val变量由于不可变性,因此委托声明的变量和val声明的变量可以共用一个全局变量,无需各自声明(编译器很聪明,不会变因此使用一个就好)、
但是对于var修饰的变量来说,其可变性导致需要额外声明一个变量用于属性的get和set,而委托也需要一个委托的实例因此会声明两个全局变量,委托路由的变量和属性的变量两个互不干扰!!!
一定要注意,在coding过程中很容易认为修改类内部的属性会导致路由发生变化,其实并不然 路由是路由单独的变量,属性是属性单独的变量
val 配合委托code:
由于val只有get方法没有set方法因此val创建的全局变量可以和委托公用一个
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty implements IDelegate {
@NotNull
private final DelegateImplClass delegateClass;
@NotNull
public final DelegateImplClass getDelegateClass() {
return this.delegateClass;
}
public DelegateClassByProperty(@NotNull DelegateImplClass delegateClass) {
Intrinsics.checkNotNullParameter(delegateClass, "delegateClass");
super();
this.delegateClass = delegateClass;
}
public void eat() {
this.delegateClass.eat();
}
public void sleep() {
this.delegateClass.sleep();
}
}
-----------------------------------《End》---------------------------------------------
委托var属性的code”
-----------------------------------《Start》---------------------------------------------
public final class DelegateClassByProperty implements IDelegate {
@NotNull
private DelegateImplClass delegateClass;
// $FF: synthetic field
private final DelegateImplClass $$delegate_0;
@NotNull
public final DelegateImplClass getDelegateClass() {
return this.delegateClass;
}
public final void setDelegateClass(@NotNull DelegateImplClass var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.delegateClass = var1;
}
public DelegateClassByProperty(@NotNull DelegateImplClass delegateClass) {
Intrinsics.checkNotNullParameter(delegateClass, "delegateClass");
super();
this.$$delegate_0 = delegateClass;
this.delegateClass = delegateClass;
}
public void eat() {
this.$$delegate_0.eat();
}
public void sleep() {
this.$$delegate_0.sleep();
}
}
-----------------------------------《End》---------------------------------------------
kotlin中常见的内置委托
上面的写法都是直接声明的一个实例,emm不怎么好协写成声明式的调用方法更容易理解,也更优雅
kotlin中场景的by lazy和observe都是类似上面的实现,读者自行分析吧(狗头,看完实现原理也能猜出个大概了哈哈)
更多推荐



所有评论(0)