1. 扩展属性
kotlin允许动态为类扩展属性,扩展属性是通过添加get、set方法实现,没有幕后字段(filed)。 扩展属性也没有真的为该类添加了属性,只能说是为该类通过get、set方法计算出属性。 限制:①扩展属性不能有初始值; ②扩展属性不能用filed关键字访问幕后字段; ③val必须提供get方法,var必须提供get和set方法。
var类型
class ExtensionTest(var param1: String, var param2: String)
var ExtensionTest.extensionParam: String
set(value) {
param1 = "param1$value"
param1 = "param2$value"
}
get() = "$param1-$param2"
fun main(args: Array<String>) {
val extensionTest = ExtensionTest("a", "b")
println(extensionTest.param1)
println(extensionTest.param2)
println(extensionTest.extensionParam)
}
val类型
val Float.dp
get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this,
Resources.getSystem().displayMetrics
)
...
val RADIUS = 200f.dp
2. 扩展函数的写法
fun String.method1(i: Int) {
...
}
这里要扩展函数的类名叫做Receiver(接受者),也就是谁可以去调用它.
在声明一个函数的时候在函数名的左边写个类名再加个点,你就能对这个类的对象调用这个函数了。这种函数就叫扩展函数,Extension Functions。就好像你钻到这个类的源码里,改了它的代码,给它增加了一个新的函数一样。虽然事实上不是,但用起来基本一样。
注意:
- 如果被扩展的类的扩展方法与该类的成员方法名字和参数一样,该类对象调用该方法时,调用的会是成员方法。
- 由于静态调用扩展方法是在编译时执行,因此,如果父类和子类都扩展了同名的一个扩展方法,引用类型均为父类的情况下,会调用父类的扩展方法。
3 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,不属于任何类——确切地说是,不是任何一个类的成员函数——但我要限制只有通过某个类的对象才能调用你。这就是扩展函数的本质。
4 成员扩展函数
写在类里的扩展函数 , 你可以在这个类里调用这个函数,但必须使用那个前缀类的对象(Receiver)来调用它
class Example {
fun String.method2(i: Int) {
...
}
"rengwuxian".method2(1)
}
成员扩展函数是属于谁呢? —
它既是外部类的成员函数,又是前缀类的扩展函数. 它的作用域是类内部, 他的Receiver是点左侧的类
这个「属于谁」其实有点模糊的,我需要问再明确点: 它是谁的成员函数?当然是外部的类的成员函数了,因为它写在它里面嘛, 那函数名左边的是什么?它是这个函数的 Receiver,对吧?也就是谁可以去调用它。 所以它既是外部类的成员函数,又是前缀类的扩展函数。
5 指向扩展函数的引用
函数是可以使用双冒号被指向的, 双冒号加方法名 指向的并不是函数本身,而是和函数等价的一个对象, 我们通常可以把这个「指向和函数等价的对象的引用」称作是「指向这个函数的引用」
顶层扩展函数的 指向扩展函数的引用
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 就干脆不许我们引用既是成员函数又是扩展函数的函数了,一了百了。
fun Extensions .method2(i: Int) {
...
}
class Extensions {
fun String.method1(i: Int) {
...
}
fun method2(i: Int) {
...
}
String::method1
}
class Example {
Extensions ::method1
Extensions ::method2
}
6 把扩展函数的引用赋值给变量
扩展函数的引用也可以赋值给变量, 然后你再拿着这个变量去调用,或者再次传递给别的变量,都是可以的 跟普通函数的引用一样,扩展函数的引用也可以被调用,直接调用或者用 invoke() 都可以,不过要记得把 Receiver 也就是接收者或者说调用者填成第一个参数
val a: String.(Int) -> Unit = String::method1
"zhf".a(1)
a("zhf", 1)
a.invoke("zhf", 1)
7 有无 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/ https://www.cnblogs.com/nicolas2019/p/10932131.html
|