Kotlin基础(5)-扩展属性和扩展函数

前言

本文介绍Kotlin扩展函数与扩展属性的相关方法

扩展属性

首先看如下的一段代码:

  var<T> MutableList<T>.charValue:T
      get() {return  this[0]}
      set(value) {this[0]=value}

  val list = mutableListOf<Int>(1, 2, 3)
        val value=list.charValue
        println(value)

测试结果

11-01 15:27:02.861 4257-4257/? I/System.out: 1

形式: XXX.YYY:ZZZ
其中XXX成为传播者类型,YYY为扩展属性的名称,ZZZ为扩展属性的类型

扩展属性实际上就是提供某个属性访问的set,get方法,这两个set,get方法是静态函数,同时都会传入一个接收者类型的对象,然后在其内部用这个对象实例去访问和修改对象所对应的类的属性。在本例中就是提供了set和get方法,并将MutableList传入,这样就获取到了MutableList的实例,通过对该实例的操作实现修改或获取MutableList的属性

java字节码如下

  public final Object getCharValue(@NotNull List $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.get(0);
   }

   public final void setCharValue(@NotNull List $receiver, Object value) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      $receiver.set(0, value);
   }

需要注意的是如果扩展的属性与扩展类的属性冲突,则优先使用扩展类的属性

class A(){
         var x:Int=100
         set(value){
             field=value
         } get(){
            return field
        }
    }

    val A.x:Int
        get() = 110;

测试结果

11-01 17:27:07.129 10252-10252/com.zhqy.javademo I/System.out: 100

扩展函数

扩展函数与扩展属性在原理上相似,将传播者类型的实例出入静态方法中,通过对该对象进行操作来实现扩展类的效果,类似于装饰者模式增强类的功能。

代码如下:

  fun TextView.setDefaultTextColor(color:Int):TextView{
        this.setTextColor(resources.getColor(color))
        return this
    }

   tv=findViewById(R.id.tv)
        tv.setDefaultTextColor(R.color.red)

java字节码

 public final void setDefaultTextColor(@NotNull TextView $receiver, int color) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      $receiver.setTextColor($receiver.getResources().getColor(color));
   }

从字节码中可以看出,第一个参数传入了一个Textiew的实例,即调用该方法的TextView实例,通过对该对象设置字体颜色,实现了改变字体颜色的效果。但需要注意的是扩展属性和扩展方法只有在调用它时才会有效果,且作用效果只针对调用它的对象实例

DR和ER

什么事DR和ER呢?DR 指的是分发接收者(Dispatcher Receiver),ER指的是扩展接收者(Extention Receiver)。扩展接收者指的是哪个类型的对象调用该扩展方法,该对象就是扩展接收者,声明扩展函数和属性的类被称为分发接收者,那么两者的含义又是什么呢?

先看一个扩展接收者(ER)的例子

  open class A(){
       open var x:Int=100;
    }


    class A1():A(){
       
    }


    fun A.printX(){
        println("${this.x} in A")
    }

    fun A1.printX(){
        println("${this.x} in A1")
    }

    fun printx(a:A){
        a.printX()
    }

   var a=A1();
        println(a.x)
        printx(a);

代码中声明了一个类A和A1 其中A1继承自A,声明了A的扩展函数和A1的扩展函数,并声明了printx来调用扩展函数,在调用时声明了一个A1的实例a并调用printx来调用扩展函数。因为声明了A1的扩展函数printX,所以应该打印${this.x} in A1这行文字,那么测试结果是否和我们预期的一样呢?

11-01 16:38:32.521 8605-8605/com.zhqy.javademo I/System.out: 100 in A

测试结果与我们预期的不一致,他并没有调用A1的扩展方法,而是调用其父类的A的扩展方法,这是为什么呢?这是因为扩展接收者遵循静态调用的原则,接收者类型由声明时决定,即你声明时传入的是什么类型的对象,就调用该对象对应的扩展方法或属性,在代码中 printx(a:A)放传入的参数是A类型的对象,所以调用的是A类型的扩展方法。

现在看一下DR的例子

open class A(){

}

class A1():A(){

}

open class B(){
    open fun A.foo(){
        println("A的扩展方法,在B中声明")
    }

    open fun A1.foo(){
        println("A1的扩展方法,在B中声明")
    }

    open fun call(a:A){
        a.foo()
    }
}

open class B1():B(){
    override fun A.foo(){
        println("A的扩展方法,在B1中声明")
    }

    override fun A1.foo(){
        println("A1的扩展方法,在B1中声明")
    }

    override fun call(a:A){
        a.foo()
    }
}


  var a=A();
         var a1=A1();
         var b=B();
         var b1=B1();

        b.call(a)
        b.call(a1)
        b1.call(a)
        b.call(a1);

在B和B1中有调用A或A1的扩展函数的方法call(A a),以及声明的A和A1的扩展函数,由于扩展接收者遵循类型由声明时决定,而call中传入的参数声明的是A类型,故执行A的扩展方法而不会执行其子类声明的扩展方法。那么会调用B还是B1关于A的扩展方法呢?这里引出分发接收者的定义,分发接收者指的是如果类中定义了其他类的扩展方法,那么这个类成为分发接收者,分发接收者遵循动态调用的原则,即接收者类型由运行时决定,即call方法在那个类中就执行哪个类中针对A的扩展方法。
测试结果如下:

11-01 17:17:28.445 9273-9273/com.zhqy.javademo I/System.out: A的扩展方法,在B中声明
11-01 17:17:28.446 9273-9273/com.zhqy.javademo I/System.out: A的扩展方法,在B中声明
11-01 17:17:28.446 9273-9273/com.zhqy.javademo I/System.out: A的扩展方法,在B1中声明
11-01 17:17:28.446 9273-9273/com.zhqy.javademo I/System.out: A的扩展方法,在B中声明

与我们分析的一致。

以上就是扩展属性和扩展函数的全部内容

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,565评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,021评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,003评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,015评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,020评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,856评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,178评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,824评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,264评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,788评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,913评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,535评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,130评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,102评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,334评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,298评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,622评论 2 343