介绍
kotlin中有一个神秘的符号“::”,双冒号,我们在项目中常见也经常使用的地方就是ClassA::class,这里我们获取到了ClassA的引用,那么双冒号的作用是不是就是获取类的引用呢?是,但不仅仅是。
引用的分类
类引用
开头所说的例子就是通过::class获取类的引用
val c = MyClass::class
而要实现java类引用的效果,则需要添加.java成为::class.java。
val c = MyClass::class.java
属性引用
类的属性作为对象来使用,可以使用::操作符
var x = 1
fun main() {
::x.set(2)
print(x)
}
访问类的成员属性时,可以使用类名+双冒号+属性的方式进行限定,将属性引用存储在显式指定类型的变量中
class KtTest(val age: Int)
fun main() {
val temNum = KtTest::age
print(temNum.get(KtTest(3)))
}
函数引用
普通函数引用
fun isOdd(x: Int) = x % 2 != 0
对于这个函数,可以直接使用 isOdd(5) 进行调用,但是当这个方法作为参数时,就可以使用函数引用来调用
fun isOdd(x: Int) = x % 2 != 0
fun test() {
val numbers = listOf(1, 2, 3)
numbers.filter(::isOdd)
}
看源码,filter操作符接收的是一个lambda参数
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
return filterTo(ArrayList<T>(), predicate)
}
众所周知,kotlin里的方法等价于一个lambda,所以可以把isOdd方法作为参数传递进去,但是要注意条件:只有方法的参数与返回值和lambda一样,才可以作为参数传递。
构造函数引用
当需要的函数类型与构造函数的参数类型、返回值一样时,构造函数也可以以引用方式调用。
fun showName(num: Int): Boolean = num % 2 == 0
class KtTest {
fun main() {
getKtTest(::KtTest)
}
}
fun getKtTest(kt: () -> KtTest){
val ktTest = kt()
}
顶层函数引用
顶层函数也可以作为参数被使用。
fun showName(num: Int): Boolean = num % 2 == 0
class KtTest {
fun main() {
val data = listOf(1, 2, 4)
data.filter(::showName)
}
}
拓展函数引用
同样的,拓展函数也可以通过引用调用
fun String.hasNumber(): Boolean {
var hasNumber = false
this.forEach {
hasNumber = it >= '0' || it <= '9'
}
return hasNumber
}
val str = "AB2C"
val hasNumbers = str::hasNumber
引用绑定
方法引用绑定
kotlin允许使用特定的引用语法获取实例对象上的方法引用,格式为:对象实例 :: 成员
fun main() {
val numberRegex = "\d+".toRegex()
println(numberRegex.matches("26"))
//存储numberRegex的引用,这时numberRegex的引用被绑定到了接收者numberRegex上
val isNumber = numberRegex::matches
println(isNumber("26"))
}
我们不是直接调用matches()方法,而是存取对它的引用,这样的引用会被绑定到其接收者身上,它可以直接调用(如上例所示),或者用于任何期待一个函数类型表达式的时候
fun main() {
val numberRegex = "\d+".toRegex()
val strings = listOf("abc", "124", "a70")
println(strings.filter(numberRegex::matches))
}
比较绑定的类型和相应的未绑定类型的引用(即上面的两种使用方式), 绑定的可调用引用有其接收者“附加”到其上,因此接收者的类型不再是参数:
\已绑定
val isNumber: (CharSequence) -> Boolean = numberRegex::matches
\未绑定
val matches: (Regex, CharSequence) -> Boolean = Regex::matches
属性引用绑定
fun main() {
val prop = "abc"::length
println(prop.get())
}
无需显式指定 this
作为接收者:this::foo
与 ::foo
是等价的。
构造函数引用的绑定
class Outer {
inner class Inner
}
val o = Outer()
val boundInnerCtor = o::Inner
内部类构造函数绑定的可调用引用可通过提供外部类的实例来获得