Kotlin学习笔记(8)- 扩展

系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,欢迎关注我,我们一起学习进步!
Kotlin学习笔记(1)- 环境配置
Kotlin学习笔记(2)- 空安全
Kotlin学习笔记(3)- 语法
Kotlin学习笔记(4)- 流程控制
Kotlin学习笔记(5)- 类
Kotlin学习笔记(6)- 属性
Kotlin学习笔记(7)- 接口
Kotlin学习笔记(8)- 扩展
Kotlin学习笔记(8)- 扩展(续)
Kotlin学习笔记(9)- 数据类
Kotlin学习笔记(10)- 泛型
Kotlin学习笔记(11)- 内部类和嵌套类
Kotlin学习笔记(12)- 委托
Kotlin学习笔记(13)- 函数式编程
Kotlin学习笔记(14)- lambda

今天要开始学习扩展(Extension)了,扩展是kotlin中非常重要的一个特性,它能让我们对一些已有的类进行功能增加、简化,使他们更好的应对我们的需求。这么说可能有点枯燥,我们先来看一个小栗子。

//  对Context的扩展,增加了toast方法。为了更好的看到效果,我还加了一段log日志
fun Context.toast(msg : String){
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
    Log.d("text", "Toast msg : $msg")
}

// Activity类,由于所有Activity都是Context的子类,所以可以直接使用扩展的toast方法
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ......
        toast("hello, Extension")
    }
}

// 输出
Toast msg : hello, Extension

怎么样,有没有一点小激动,反正我是有的。按照通常的做法,我们会写一个ToastUtils工具类,或者在BaseActivity中实现toast方法,但是现在这些统统不需要了,直接给Context增加扩展,这样不论是Activity或者Service都可以直接调用,更简洁、更优雅。接下来是我的学习进程,希望也能对你有所帮助。

一、扩展方法(Extension Function)

扩展方法,顾名思义,就是对类的方法进行扩展,写法和定义方法类似,但是要声明目标类,也就是对哪个类进行扩展,kotlin中称之为Top Level。就比如上面的栗子。

fun Context.toast(msg : String){
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
    Log.d("text", "Toast msg : $msg")
}

其中,Context就是目标类(Top Level),我们把它放到方法名前,用点.表示从属关系。在方法体中,用关键字this对本体进行调用。和普通方法一样,如果有返回值,在方法后面跟上返回类型,我这里没有返回值,所以直接省略了。

还有一点很神奇的是,我们可以允许目标类接受null。不是说对null进行扩展,而是可以设置目标类为一个可以为空的对象。再举一个栗子,也是我们很常用的功能:

fun Any?.string() : String = if(this == null) "null obj" else toString()

var a = 1
toast("hello, ${a.string()}")
var b : View? = null
toast("hello, ${b.string()}")

// 输出
Toast msg : hello, 1
Toast msg : hello, null obj

在这里我们对Any进行扩展,它在konlin中类似于java中的Object,所有的类都继承与它,我们给它扩展了一个string()方法。还记得吗,类型后面跟问号?表示可为空。在这里当目标为null时,我们返回了一个字符串,看一下调用,再看一下输出,完全和预想的一样。

kotlin中其实已经默认对toString方法进行了处理,如果是空,则会返回字符串null。这其实很多时候不符合我们的需求,我们可以自己扩展一下,将返回值改为空字符串就好。

fun Any?.string() : String = if(this == null) "" else toString()

二、扩展属性(extension property)

扩展属性和扩展方法类似,是对目标类的属性进行扩展。扩展属性也会有setget方法,并且要求实现这两个方法,不然会提示编译错误。因为扩展并不是在目标类上增加了这个属性,所以目标类其实是不持有这个属性的,我们通过getset对这个属性进行读写操作的时候也不能使用field指代属性本体。可以使用this,依然表示的目标类。

// 扩展了一个属性paddingH
var View.panddingH : Int
    get() = (paddingLeft + paddingRight) / 2
    set(value) {
        setPadding(value, paddingTop, value, paddingBottom)
    }

// 设置值
text.panddingH = 100

在栗子中,我们首先给View扩展了一个属性paddingH,并给属性增加了setget方法,然后再activity中通过textview调用。

三、静态扩展

  1. kotlin中的静态用关键字companion表示,而且它不是修饰属性或方法,而是定义一个方法块,在方法块中的所有方法和属性都是静态的,这样就将静态部分统一包装了起来。静态部分的访问和java一致,直接使用类名+静态属性/方法名就可以

    // 定义静态部分
    class Extension {
        companion object part{
            var name = "Extension"
        }
    }
    
    // 通过类名+属性名直接调用
    toast("hello, ${Extension.name}")
    
    // 输出
    Toast msg : hello, Extension
    

    上面栗子中,companion object一起是修饰关键字,part是方法块的名称。其中,方法块名称part可以省略,如果省略的话,默认缺省名为Companion

  2. 静态的扩展和普通的扩展类似,但是在目标类要加上静态方法块的名称,所以如果我们要对一个静态部分扩展,就要先知道静态方法块的名称才行。

    class Extension {
        companion object part{
            var name = "Extension"
        }
    }
    
    // part为静态方法块名称
    fun Extension.part.upCase() : String{
        return name.toUpperCase()
    }
    
    // 调用一下
    toast("hello, ${Extension.name}")
    toast("hello, ${Extension.upCase()}")
    
    //输出
    Toast msg : hello, Extension
    Toast msg : hello, EXTENSION
    

四、引用

在AS中,如果我们使用扩展方法和扩展属性,大部分情况下会自动提示导入import,但有时候如果没有提示,就需要手动import一下了。扩展的import路径为:包名+方法名/属性名,比如我最先创建的扩展方法toast,其实文件全部是这样的

package com.study.jcking.weatherkotlin.exec

import android.content.Context
import android.util.Log
import android.widget.Toast

/**
 * Created by Jcking on 2017/6/3.
 */
fun Context.toast(msg : String){
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
    Log.d("text", "Toast msg : $msg")
}

可见,toast方法没有在类内部,而是与包名同级,当然这不是绝对,只是习惯这样写,那我们引用的时候就这样写import

import com.study.jcking.weatherkotlin.exec.toast

五、最后

以上就是个人学习扩展的一些总结,东西不多,但是感觉是kotlin中很重要的一部分。他让我们的代码更简洁,更优雅,而且功能定位更准确、更清晰。再有,就是感觉一大波util要下岗了~

最后抛出个问题,暂时还没有搞明白,希望小伙伴们帮我解惑:如果我将扩展没有放在包名同级,而是放在一个类的内部,在语法上是完全没有问题的,但是类外部调用却好像不行了。请问是它失去了对外部的可见性,还是我的调用方式有问题?欢迎讨论指教,先行谢过!!

更新:2017年6月4日
问题已经找到资料了,确实是不行的,请看我下一篇笔记: Kotlin学习笔记(8)- 扩展(续)

Extension类,包package com.study.jcking.weatherkotlin.exec

package com.study.jcking.weatherkotlin.exec

class Extension {
    companion object part{
        var name = "Extension"
    }

    fun Context.toast(msg : String){
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
        Log.d("text", "Toast msg : $msg")
    }
}

调用类,包package com.study.jcking.weatherkotlin

package com.study.jcking.weatherkotlin

class MainActivity : AppCompatActivity() {

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

推荐阅读更多精彩内容