首先申明下,本文为笔者学习《Kotlin 程序开发入门精要》的笔记,并加入笔者自己的理解和归纳总结。
1. 扩展
1.1 类成员扩展
扩展可以向类中添加成员。为Long
添加一个format
方法,用于时间戳格式化输出。
fun Long.format(): String {
return SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
.format(Date(this * 1000))
}
fun main(args : Array<String>) {
var time : Long = 1585891747
println(time.format()); // 2020-04-03 01:29:07
}
因为open
不能用于顶层函数,所以扩展不能用于继承。
open class Super {
}
class Child : Super() {
}
fun Super.add(value : Int) = value + 10
fun Child.add(value : Int) = value + 100
fun main(args : Array<String>) {
var s1 : Super = Super()
var s2 : Super = Child()
var s3 : Child = Child()
println(s1.add(5)) // 15
println(s2.add(5)) // 15
println(s3.add(5)) // 105
}
如果通过扩展向类中添加的成员函数与类中原来的成员函数的结构完全相同,内部成员函数的优先级更高。
class Operation {
fun add(value : Int) : Int {
return value + 10
}
}
fun Operation.add(value : Int) : Int {
return value + 100
}
fun main(args : Array<String>) {
var op = Operation()
println(op.add(5)) // 15
}
1.2 类属性扩展
扩展属性没有backing field
属性,因此保存和获取属性值都需要一个类成员变量。
class Operation {
var i:Int = 0
}
var Operation.value : Int
get() = i
set(v : Int) {
i = v
}
fun main(args : Array<String>) {
var op = Operation()
op.value = 10
println(op.value) // 10
}
1.3 伴随对象扩展
可以为伴随对象添加成员
class Shape {
companion object Factory {
}
}
fun Shape.Factory.create() : Shape {
return Shape()
}
fun main(args : Array<String>) {
var s = Shape.create()
}
1.4 类中扩展
在类中也可以使用扩展
open class Base {
fun sub() {
println("Base.sub")
}
}
open class BaseHolder {
open fun Base.add() {
println("Base.add in BaseHolder")
}
fun test(b : Base) {
b.add()
b.sub()
}
}
fun main(args : Array<String>) {
BaseHolder().test(Base())
}
输出
Base.add in BaseHolder
Base.sub
类中的扩展可以被继承
open class SubHolder : BaseHolder() {
override fun Base.add() {
println("Base.add in SubHolder")
}
}
fun main(args : Array<String>) {
// BaseHolder().test(Base())
SubHolder().test(Base())
}
输出
Base.add in SubHolder
Base.sub
2. 委托
委托可以将代码放在同一个地方,以便被多个类和属性重用。
2.1 类的委托
通过使用by
关键字来实现类的委托。Car
继承(Engine)
,通过by
关键字把run()
方法委托给一个对象(Engine)
,这个对象通过主构造器传入。
interface Engine {
fun run()
}
class EngineImpl : Engine {
override fun run() {
println("Engine run")
}
}
class Car(engine : Engine) : Engine by engine {
}
fun main(args : Array<String>) {
Car(EngineImpl()).run()
}
2.2 类属性委托
类属性委托需要创建委托类,委托类需要创建getValue()
和setValue()
两个函数,函数使用operator
声明。
import kotlin.reflect.KProperty
class Teacher {
// 将name属性委托给Delegate类
var name: String by Delegate()
}
class Student {
// 将name属性委托给Delegate类
var name: String by Delegate()
}
class Delegate {
var name: String = ""
operator fun getValue(thisRef : Any?, property : KProperty<*>) : String {
println("Delegate.getValue 被调用")
return name
}
operator fun setValue(thisRef : Any?, property : KProperty<*>, value : String) {
println("Delegate.setValue 被调用")
this.name = value;
}
}
fun main(args: Array<String>) {
var t: Teacher = Teacher()
t.name = "Mike"
println(t.name)
var s: Student = Student()
s.name = "Jack"
println(s.name)
}
输出
Delegate.setValue 被调用
Delegate.getValue 被调用
Mike
Delegate.setValue 被调用
Delegate.getValue 被调用
Jack
可以向委托类的主构造传入一个初始化函数,initializer
是初始化函数,返回对应类名
class Teacher {
var name: String by Delegate {
"Teacher"
}
}
class Student {
var name: String by Delegate {
"Student"
}
}
class Delegate<T>(initializer : () -> T) {
var name: String = ""
var className = initializer()
operator fun getValue(thisRef : Any?, property : KProperty<*>) : String {
println("${className}.getValue 被调用")
return name
}
operator fun setValue(thisRef : Any?, property : KProperty<*>, value : String) {
println("${className}.setValue 被调用")
this.name = value;
}
}
fun main(args: Array<String>) {
var t: Teacher = Teacher()
t.name = "Mike"
println(t.name)
var s: Student = Student()
s.name = "Jack"
println(s.name)
}
输出
Teacher.setValue 被调用
Teacher.getValue 被调用
Mike
Student.setValue 被调用
Student.getValue 被调用
Jack
2.3 标准委托
惰性加载
lazy
接受一个表达式作为参数,第一次调用时执行表达式,并记住执行结果。后面所用的调用只会返回记住的结果。
val value : String by lazy {
println ("lazy load")
"Hello World"
}
fun main(args : Array<String>) {
println(value)
println(value)
}
输出
lazy load
Hello World
Hello World
可观察属性
Delegates.observable
实现可观察属性值变化。
class Person {
// Mike是初始值
var name : String by Delegates.observable("Mike") {
prop, oldValue, newValue ->
println("oldValue = $oldValue, newValue = $newValue")
}
}
fun main(args : Array<String>) {
var p = Person()
p.name = "Jack"
p.name = "Peter"
}
输出
oldValue = Mike, newValue = Jack
oldValue = Jack, newValue = Peter
可阻止属性赋值
Delegates.voteable
能够拦截属性赋值操作。voteable
函数会返回一个布尔类型的值,如果是true
,表示允许给属性赋值。
class Person {
var name : String by Delegates.vetoable("Mike") {
prop, oldValue, newValue ->
println("oldValue = $oldValue, newValue = $newValue")
var result = true
if (newValue.equals("Peter")) {
result = false
}
result
}
}
fun main(args : Array<String>) {
var p = Person()
p.name = "Jack"
p.name = "Peter"
println(p.name)
}
输出
oldValue = Mike, newValue = Jack
oldValue = Jack, newValue = Peter
Jack
Map委托
Map委托
通过将Map
中的key
的值映射到同名的属性中。
class Person (var map : Map<String, Any>) {
val name : String by map
val age : Int by map
}
fun main(args : Array<String>) {
var map = mapOf(
"name" to "Mike",
"age" to 25
)
var p = Person(map)
println(p.name)
println(p.age)
}
输出
Mike
25
MutableMap委托
MutableMap委托
可以和属性值同步变化
class Person (var map : MutableMap<String, Any>) {
var name : String by map
var age : Int by map
}
fun main(args : Array<String>) {
var map = mutableMapOf(
"name" to "Mike",
"age" to 25
)
var p = Person4(map)
println(p.name)
println(p.age)
map.put("name", "Jack")
println(p.name)
p.age = 35
println(map)
}
输出
Mike
25
Jack
{name=Jack, age=35}