Android kotlin 杂项

1 字符串可以包含模板表达式 , 模板表达式以美元符( $ )开头。

val i = 10
val s = "i = $i" // 求值结果为 "i = 10"

2 引用相等

引用相等由 ===(以及其否定形式 !== )操作判断。a === b 当且仅当 a 和 b 指向同一个对象时求值为 true。

3 结构相等

结构相等由 ==(以及其否定形式 != )操作判断;
按照惯例,像 a == b 这样的表达式会翻译成

a?.equals(b) ?: (b === null)

4 幕后字段,field

Kotlin 中类不能有字段。当使自定义定义访问器时,有时有个幕后字段(backing field)有时是必要的。为此 Kotlin 提供一个自动幕后字段,它可通过使用 field 标识符访问;

var counter = 0 // 此初始器值直接写⼊到幕后字段
set(value) {
    if (value >= 0)
        field = value
}

5 幕后属性

private var _table: Map? = null
public val table: Map
    get() {
        if (_table == null) {
            _table = HashMap() // 类型参数已推断出
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

6 惰性初始化属性,lateinit
如果在定义变量时(例如定义成员变量),又想该变量不为空,又不想子定义时就初始化

该修饰符只能在类体中(不是在主构造函数中)声明的 var 属性,并且仅当该属性没有定义 getter 或 setter 时。

该属性必须是非空类型,并且不能是原生类型。

public class MyTest {
    lateinit var subject: TestSubject
    @SetUp fun setup() {
        subject = TestSubject()
    }
    @Test fun test() {
        subject.method() // 直接解引⽤
    }
}

7 扩展是静态解析

扩展不能真正的修改他们所扩展的类。通过定义一个扩展,你并没有在这个类中插入新成员, 仅仅是可以通过该类型的变量点表达式去调用这个新函数;

如果定义有成员函数和扩展函数,这两个函数有相同的接收者类型、相同的名字并且都适给定的参数,这种情况总是取成员函数。

结果是C

open class C
class D: C()
    fun C.foo() = "c"
    fun D.foo() = "d"
    fun printFoo(c: C) {
    println(c.foo())
}
printFoo(D())

可空接收者扩展

可以为可空的接收者类型定义扩展。

fun Any?.toString(): String {
    if (this == null) return "null"
    // 空检测之后,“this”会⾃动转换为⾮空类型,所以下⾯的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}

8 扩展属性的行为只能通过明确给定的取值方法与设值方法来定义。

val  List.lastIndex: Int
    get() = size - 1

9 扩展声明为成员

class D {
    fun bar() { …… }
}
class C {
    fun baz() { …… }
    fun D.foo() {
        bar() // 调D.bar,其中的对象成员可以无需通过限定符访问
        baz() // 调C.baz
    }
}

扩展声明所在的类的实例称为分发接收者,

扩展方法调用所在的接收者类型的实例称为扩展接收者 。

对于分发接收者和扩展接收者的成员名字冲突的情况,扩展接收者优先。

限定的 this语法,可以区分函数

class C {
fun D.foo() {
    toString() // 调 D.toString()
    [email protected]() // 调C.toString()
}

10 类型的检查与转换

is 和 !is 操作符

智能转换

fun demo(x: Any) {
if (x is String) {
    print(x.length) // x 自动转换为字符串
}
}

11 “不安全的”转换操作符---as
如果转换是不可能的,转换操作符会抛出异常

12 “安全的(” 可空)转换操作符--as?
转换失败返回null

13 解构声明

所谓的解构声明就是将一个对象解构(destructure)为多个变量,也就是意味着一个解构声明会一次性创建多个变量.简单的来说,一个解构声明有两个动作:

声明了多个变量

将对象的属性值赋值给相应的变量

可以从一个函数返回多个变量

数据类,
data class Person(var name: String, var age: Int) {
}
当我们对Person的实例使用解构声明时,可以这样做:

var person: Person = Person("Jone", 20)
var (name, age) = person

println("name: $name, age: $age")// 打印:name: Jone, age: 20

对于非数据类,需要自定义componentN
data class Person(var name: String, var age: Int, var addr: String) {
        var mobile: String ?= null

    operator fun component4(): String {
        return this.mobile!!
    }
}

14 延迟初始化

val p: String by lazy {
// 计算该字符串
}

15 对一个对象实例调用多个方法( with)

class Turtle {
fun penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}
val myTurtle = Turtle()
with(myTurtle) { // 画⼀个 100 像素的正⽅形
penDown()
for(i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}

你可能感兴趣的:(Android kotlin 杂项)