1. 扩展函数的写法
// fun 关键字 + 要扩展的类名 + 点号 + 方法名 + 方法属性
fun String.method1(i: Int) {
...
}
这里要扩展函数的类名叫做Receiver(接受者),也就是谁可以去调用它.
在声明一个函数的时候在函数名的左边写个类名再加个点,你就能对这个类的对象调用这个函数了。这种函数就叫扩展函数,Extension Functions。就好像你钻到这个类的源码里,改了它的代码,给它增加了一个新的函数一样。虽然事实上不是,但用起来基本一样。
Top Level扩展函数
package com.zhf
fun String.method1(i: Int) {
...
}
// 在使用的地方调用就可以了
"rengwuxian".method1(1)
Top Level扩展函数是属于谁呢?
它既是Top Level函数,又是前缀类的扩展函数, 它的作用域是package包内部, 他的Receiver是点左侧的类
看了很多教程和解释, 自己理解其实这个函数就是个顶层函数,它只属于它所在的 package, 不过他只能被Receiver(接收者)使用, 就是上面代码里的String,
虽然说它是个 Top-level Function,不属于任何类——确切地说是,不是任何一个类的成员函数——但我要限制只有通过某个类的对象才能调用你。这就是扩展函数的本质。
成员扩展函数
写在类里的扩展函数 , 你可以在这个类里调用这个函数,但必须使用那个前缀类的对象(Receiver)来调用它
class Example {
fun String.method2(i: Int) {
...
}
"rengwuxian".method2(1) // 可以调用
}
成员扩展函数是属于谁呢? —
它既是外部类的成员函数,又是前缀类的扩展函数. 它的作用域是类内部, 他的Receiver是点左侧的类
这个「属于谁」其实有点模糊的,我需要问再明确点:
它是谁的成员函数?当然是外部的类的成员函数了,因为它写在它里面嘛,
那函数名左边的是什么?它是这个函数的 Receiver,对吧?也就是谁可以去调用它。
所以它既是外部类的成员函数,又是前缀类的扩展函数。
指向扩展函数的引用
函数是可以使用双冒号被指向的, 双冒号加方法名 指向的并不是函数本身,而是和函数等价的一个对象,
我们通常可以把这个「指向和函数等价的对象的引用」称作是「指向这个函数的引用」
顶层扩展函数的 指向扩展函数的引用
fun String.method1(i: Int) {
}
String::method1
上面 String::method1 就是指向扩展函数的引用, 它其实是可以作为对象来传递和使用的,当然它也可以作为参数,传递给方法, 这就是高阶函数了
注意: 以下代码中 method3 和 method4 为什么都可以 传如String 的函数引用 下文会说到
fun String.method1(i: Int): String {
}
class Example {
val a = String::method1
val b = a
method3(String::method1)
method3(b)
method4(String::method1)
method4(b)
fun method3(method: String.(Int) -> String) {}
fun method4(method: (String, Int) -> String) {}
}
成员扩展函数的 指向扩展函数的引用 ( *** 不存在)
一个成员函数怎么引用:类名加双冒号加函数名对吧?扩展函数呢?也是类名加双冒号加函数名对吧?只不过这次是 Receiver 的类名。那成员扩展函数呢?还用类名加双冒号加函数名呗?但是……用谁的类名?是这个函数所属的类名,还是它的 Receiver 的类名?这是有歧义的,所以 Kotlin 就干脆不许我们引用既是成员函数又是扩展函数的函数了,一了百了。
class Extensions {
fun String.method1(i: Int) {
...
}
fun method2(i: Int) {
...
}
String::method1 // 报错
}
class Example {
Extensions ::method1 // 报错
Extensions ::method2
}
把扩展函数的引用赋值给变量
扩展函数的引用也可以赋值给变量, 然后你再拿着这个变量去调用,或者再次传递给别的变量,都是可以的
跟普通函数的引用一样,扩展函数的引用也可以被调用,直接调用或者用 invoke() 都可以,不过要记得把 Receiver 也就是接收者或者说调用者填成第一个参数
val a: String.(Int) -> Unit = String::method1
"zhf".a(1)
a("zhf", 1)
a.invoke("zhf", 1)
有无 Receiver 的变量的互换
在 Kotlin 里,每一个有 Receiver 的函数——其实就是成员函数和扩展函数——它的引用都可以赋值给两种不同的函数类型变量:一种是有 Receiver 的,一种是没有 Receiver 的:
有 Receiver 的函数和没有 Receiver 的函数,在写法上就是把 Receiver 放在没有Receiver 的第一个参数
val a: String.(Int) -> Unit = String::method1
val b: (String, Int) -> Unit = String::method1
val c: String.(Int) -> Unit = b
val d: (String, Int) -> Unit = a
扩展 (可直接跳过)
下面三段代码,第一段代码里的 clz / clz1/ clz2/ clz3 这四个对象是一个对象吗? 他们之间有何不同呢?
- LoginActivity::class 和 mLoginActivity::class 这两个是相同的对象,
类名或者类的对象加双冒号,代表 指向扩展函数的引用 所以 clz1和clz2 是相同的对象- LoginActivity::class 返回的是什么呢 ? 在kotlin中的Class与Java不同,
kotlin中有一个自己的Class叫做KClass 双冒号加class 返回的就是 KClass- mLoginActivity::class.java 和 mLoginActivity.javaClass 这两个是相同的对象 .
第二段代码,是KClass 的一个扩展函数, 他的返回值是 Class 第三段代码,是T 的一个扩展函数, T就是某个函数名 他的返回值是 Class
结论就是: clz != clz1 == clz2 ==clz3
代码一
val clz = LoginActivity::class
val clz1 = LoginActivity::class.java
val clz2 = mLoginActivity::class.java
val clz3 = mLoginActivity.javaClass
val intent = Intent();
intent.setClass(mContext, clz1 )
startActivity(intent)
代码二
@Suppress("UPPER_BOUND_VIOLATED")
public val <T> KClass<T>.java: Class<T>
@JvmName("getJavaClass")
get() = (this as ClassBasedDeclarationContainer).jClass as Class<T>
代码三
public inline val <T : Any> T.javaClass: Class<T>
@Suppress("UsePropertyAccessSyntax")
get() = (this as java.lang.Object).getClass() as Class<T>
本文摘录自: https://rengwuxian.com/kotlin-extensions/