Kotlin 扩展
1.官方文档
https://kotlinlang.org/docs/reference/extensions.html
https://www.kotlincn.net/docs/reference/extensions.html 中文
1.1 作用
- 可以在不修改某个类的代码的情况下,对该类扩展,添加扩展函数,扩展属性。
- 可以在类内、全局作用域内对其它类扩展
- 扩展的函数、属性可以访问被扩展类的成员。
- interface,sealed,data,enum 也可以扩展
1.2 示例,对Context添加Toast功能
1 fun Context.toast(msg : String, duration : Int = Snackbar.LENGTH_SHORT){ 2 Snackbar.make(window.decorView,msg,duration).show() 3 } 4 5 override fun onTrimMemory(level: Int) { 6 super.onTrimMemory(level) 7 baseContext.toast("onTrimMemory") 8 }
2.扩展函数
2.1 自定义类 扩展函数
函数里面可以使用this,但是不可以用super
1 open class Base1{ 2 var base = 100 3 } 4 open class Source : Base1(){ 5 var COUNT = 1 6 fun fooooo() : Int { 7 return super.base.inc() 8 } 9 } 10 11 //1.自定义的类 扩展函数,里面可以使用this,但是不可以用super 12 inline fun Source.addBase(x : Int){ 13 // var ret = this.COUNT + x + super.base //error,不可以用super 14 var ret = this.COUNT + x + fooooo() 15 Log.e(TAG_EXTENSIONS, "count = ${this.COUNT} ,ret = $ret" ) 16 } 17 fun test1(){ 18 var a = Source() 19 a.addBase(3) 20 21 }
结果
2019-09-05 23:02:27.007 15205-15205/com.example.kotlin E/extensions: count = 1 ,ret = 105
2.2 扩展函数重载
1 open class Base1{ 2 var base = 100 3 } 4 open class Source : Base1(){ 5 var COUNT = 1 6 fun fooooo() : Int { 7 return super.base.inc() 8 } 9 } 10 inline fun Source.addBase(x : Int){ 11 // var ret = this.COUNT + x + super.base //error,不可以用super 12 var ret = this.COUNT + x + fooooo() 13 Log.e(TAG_EXTENSIONS, "count = ${this.COUNT} ,ret = $ret" ) 14 } 15 //2.扩展函数的重载版本 16 inline fun Source.addBase(string : String){ 17 var x = string.toInt() 18 var ret = this.COUNT + x + fooooo() 19 Log.e(TAG_EXTENSIONS, "count = ${this.COUNT} ,ret = $ret" ) 20 } 21 fun test2(){ 22 var a = Source() 23 a.addBase(3) 24 a.addBase("1000") 25 26 }
结果
2019-09-05 23:52:06.449 16731-16731/com.example.kotlin E/extensions: count = 1 ,ret = 105
2019-09-05 23:52:06.449 16731-16731/com.example.kotlin E/extensions: count = 1 ,ret = 1102
2.3 预定义类 扩展函数
1 open class Base1{ 2 var base = 100 3 } 4 open class Source : Base1(){ 5 var COUNT = 1 6 fun fooooo() : Int { 7 return super.base.inc() 8 } 9 } 10 //3.预定义的类 扩展函数 11 fun Int.add(source: Source) = source.base.dec() 12 13 fun test3(){ 14 var a = Source() 15 16 val int = 100 17 var ret = int.add(a) 18 Log.e(TAG_EXTENSIONS,"ret = $ret") 19 }
结果
2019-09-05 23:52:06.618 17524-17524/com.example.kotlin E/extensions: ret = 99
2.4 final的类也可以扩展函数
1 //4.final的类也可以扩展函数 2 fun String.add(ext : String?) : String?{ 3 return toString() + " $ext" 4 } 5 fun test4(){ 6 var str1 = "hello" 7 var str2 = "world" 8 var str3 = str1.add(str2) 9 Log.e(TAG_EXTENSIONS,"str3 = $str3") 10 }
结果
2019-09-05 23:52:27.618 17524-17524/com.example.kotlin E/extensions: str3 = hello world
2.5 父类的 扩展函数 子类可以使用
1 //5.父类的 扩展函数 子类可以使用 2 open class User{ 3 /*protected*/ 4 var age = 22 5 open fun name(){ 6 7 } 8 } 9 class EUser : User() { 10 } 11 fun User.age() : Int{ 12 return this.age 13 } 14 fun EUser.eage() : Int{ 15 return this.age 16 } 17 18 fun test5(){ 19 var user = User(); 20 var name = user.name() 21 var age = user.age() 22 var eUser = EUser() 23 24 age = eUser.age() 25 // user.eage() //error,子类的扩展函数不能用于父类 26 }
2.6 扩展函数 与多态
- 全局作用域的扩展函数不参与多态
1 //6.全局作用域的扩展函数 不参与多态 2 open class C6{ 3 open fun f6() = "c6_f6" 4 } 5 open class D6 : C6(){ 6 override fun f6() = "d6_f6" 7 } 8 9 fun C6.foo() = "c6" 10 fun D6.foo() = "d6" 11 12 fun test6(){ 13 var c6 = C6() 14 var d6 = D6() 15 var objC6 : C6 = D6() 16 17 var foo = objC6.foo() 18 var f6 = objC6.f6() 19 20 Log.e(TAG_EXTENSIONS,"foo = $foo , f6 = $f6") 21 22 }
结果
2019-09-05 23:51:00.754 18521-18521/com.example.kotlin E/extensions: foo = c6 , f6 = d6_f6
- 类内的扩展函数支持多态
1 fun test6(int: Int){ 2 3 open class A 4 5 open class Base { 6 open fun A.foo() { 7 Log.e(TAG_EXTENSIONS,"A.foo in Base.") 8 } 9 fun caller(a : A) { 10 a.foo() 11 } 12 } 13 class Derived : Base() { 14 override fun A.foo() { 15 Log.e(TAG_EXTENSIONS,"A.foo in Derived") 16 } 17 } 18 var oa = A() 19 var base = Derived() 20 base.caller(oa) 21 22 }
结果
2019-09-05 08:46:34.293 7868-7868/com.example.kotlin E/extensions: A.foo in Derived
2.7 接口支持扩展函数
但是接口实现者不用实现扩展的函数
1 //7.接口支持扩展函数,,但是不用实现扩展的函数 2 interface IF1{ 3 fun foo(){ 4 Log.e(TAG_EXTENSIONS,"c7.foo") 5 } 6 } 7 class C7 : IF1{ 8 override fun foo() { 9 super.foo() 10 Log.e(TAG_EXTENSIONS,"c7.foo") 11 } 12 } 13 fun IF1.fext(){ //接口实现者不用实现这个扩展函数 fext 14 Log.e(TAG_EXTENSIONS,"IF1.fext") 15 } 16 fun test7(){ 17 var obj = object : IF1{ 18 override fun foo() { 19 super.foo() 20 } 21 } 22 obj.fext() 23 var c7 = C7() 24 25 c7.fext() 26 }
结果
2019-09-05 23:51:00.755 18521-18521/com.example.kotlin E/extensions: IF1.fext
2019-09-05 23:51:00.755 18521-18521/com.example.kotlin E/extensions: IF1.fext
2.8 扩展函数与成员函数相同
这时,优先使用类内的同名函数。
1 //8.扩展函数与成员函数相同时,优先使用类内的同名函数。 2 open class C8{ 3 var value = 0 4 inline fun add(v : Int){ 5 this.value += v 6 Log.e(TAG_EXTENSIONS,"member.add(Int) value = $value") 7 } 8 } 9 fun C8.add(v: Int) { 10 this.value += v * 2 11 Log.e(TAG_EXTENSIONS, "extension.add(Int) value = $value") 12 } 13 fun C8.add(f: Float) { 14 this.value += (f * 2).toInt() 15 Log.e(TAG_EXTENSIONS, "extension.add(Float) value = $value") 16 } 17 18 internal fun test8(){ 19 var c8 = C8() 20 21 c8.add(2) 22 23 c8.add(3.0f) 24 25 }
结果
2019-09-05 12:54:10.717 4584-4584/com.example.kotlin E/extensions: member.add(Int) value = 2
2019-09-05 12:54:10.717 4584-4584/com.example.kotlin E/extensions: extension.add(Float) value = 8
2.9 扩展类的伴生对象
1 //9.扩展类的伴生对象 2 class C9{ 3 companion object{ 4 fun getNum() = 10 5 } 6 } 7 fun C9.Companion.foo() = 20 8 9 fun test9(){ 10 var num = C9.foo() 11 Log.e(TAG_EXTENSIONS,"C9.externion static foo = " + num) 12 }
结果
2019-09-05 12:54:10.718 4584-4584/com.example.kotlin E/extensions: C9.externion static foo = 20
2.10 用扩展重载运算符
1 data class OP3(var value: Int = 0){ 2 override fun toString() : String { 3 return value.toString() 4 } 5 } 6 operator fun OP3.plus(op3 : OP3)= OP3(value + op3.value) 7 operator fun OP3.plus(x : Int) = OP3(value + x) 8 operator fun OP3.minus(x : Int) = OP3(value - x) 9 operator fun OP3.times(x : Int) = OP3(value * x) 10 operator fun OP3.div(x : Int) = OP3(value / x) 11 operator fun OP3.rem(x : Int) = OP3(value % x) 12 13 operator fun OP3.divAssign(x : Int){ 14 value /= x 15 } 16 17 fun op_test3(){ 18 19 Log.e(TAG_OPERATOR,"____op_test3___") 20 21 var op3 = OP3() 22 Log.e(TAG_OPERATOR,"op3 = $op3") 23 24 var ret = op3 + 5 25 Log.e(TAG_OPERATOR,"op3 + 5 = $ret") 26 27 var op4 = OP3(100) 28 Log.e(TAG_OPERATOR,"op4 = $op4") 29 30 ret = op3 + op4 31 Log.e(TAG_OPERATOR,"op3 + op4 = $ret") 32 33 }
结果
2019-09-05 19:44:43.451 19781-19781/com.example.kotlin E/operator: ____op_test3___
2019-09-05 19:44:43.452 19781-19781/com.example.kotlin E/operator: op3 = 0
2019-09-05 19:44:43.452 19781-19781/com.example.kotlin E/operator: op3 + 5 = 5
2019-09-05 19:44:43.452 19781-19781/com.example.kotlin E/operator: op4 = 100
2019-09-05 19:44:43.452 19781-19781/com.example.kotlin E/operator: op3 + op4 = 100
3.扩展属性
- 扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。
- 扩展可属性 没有幕后字段(backing field),不允许被初始化,只能由显式提供的 getter/setter 定义
- 可以扩展一个val,也可以扩展一个var
3.1 扩展一个不可修改属性 val
1 class C10{ 2 fun f10(){ 3 } 4 } 5 6 //给C10 扩展一个不可修改的属性 7 val C10.SIZE : Int get() = 10 8 9 fun test10(){ 10 var c10 = C10(); 11 Log.e(TAG_EXTENSIONS,"c10.SIZE = ${c10.SIZE} ") 12 }
结果
2019-09-05 22:21:39.074 22680-22680/com.example.kotlin E/extensions: c10.SIZE = 10
3.2 扩展一个可以修改的属性 var
1 //11.给C11 扩展一个可修改的属性 2 3 class C11 4 5 internal var c11_num = 20 6 7 var C11.num : Int 8 get() { 9 return c11_num 10 } 11 set(value) { 12 c11_num = value 13 } 14 fun test11(){ 15 var c11 = C11(); 16 var num = c11.num; 17 18 c11.num = 20 * 2 19 20 Log.e(TAG_EXTENSIONS,"c10.num = ${c11.num} , num = $num ") 21 }
结果
2019-09-05 22:21:39.075 22680-22680/com.example.kotlin E/extensions: c10.num = 40 , num = 20
3.3 给Any扩展一个Context
1 val Any.HEIGHT: Int 2 get() { 3 return 33 4 } 5 6 class STU 7 val stu = STU() 8 9 val Any.ex_stu : STU //ex_stu不可变,但是它的成员可以变化 10 get() { 11 return stu 12 } 13 14 lateinit var g_context : Context 15 16 var Any.ex_context : Context 17 get() { 18 return g_context 19 } 20 set(value) { 21 }
1.在application的oncreate中初始化 g_context
2.在没有context的类中使用context
1 class LogUtil { 2 companion object { 3 ... 4 5 fun startLog(){ 6 val LOG_FILE = ex_context.getExternalFilesDir("logs").toString() + "/xxx.log" 7 try { 8 fileWriter = FileWriter(LOG_FILE,false) 9 initLogThread() 10 }catch (e : Exception){ 11 } 12 } 13 }
//... 14 }
4.扩展在类内部
扩展放在类内。不用继承,不用生成对象,就可以访问另一个类的成员 。
1 fun test13(){ 2 //不用继承,不用生成对象,就可以访问另一个类的成员 3 data class A(var name : String,var age : Int){ 4 fun id() = 1 5 fun name() = "nik" 6 } 7 data class B(var id : Int) { 8 fun A.fid(){ 9 var id = id() 10 } 11 fun A.fn(){ 12 var name = name() 13 } 14 } 15 }