Kotlin的知识点总结和一些建议

这篇文章是我在学习和使用Kotlin时的一些总结和体会,包括一些代码用来更清晰的帮助大家学习!

1、对象相关

对象表达式:相当于Java匿名类部类,在使用的地方被立即执行:

 val a = 10

val listener = object : Info("submit"),IClickListener {
    override fun doClick() {
        println("a:$a")
    }

}

listener.doClick() // 打印 a:10
//有时候我们只是需要一个没有父类的对象,我们可以这样写:
val adHoc = object {
    var x: Int = 0
    var y: Int = 0
}

print(adHoc.x + adHoc.y)
//像 java 的匿名内部类一样,对象表达式可以访问闭合范围内的变量 (和 java 不一样的是,这些变量不用是 final 修饰的)
fun countClicks(window: JComponent) {
    var clickCount = 0
    var enterCount = 0
    window.addMouseListener(object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            clickCount++
        }
        override fun mouseEntered(e: MouseEvent){
            enterCount++
        }
    })
}

对象申明:Kotlin 中我们可以方便的通过对象声明来获得一个单例,对象声明是延迟加载的, 在第一次使用的时候被初始化,对象声明不是一个表达式,不能用在赋值语句的右边,对象声明不能在局部作用域(即直接嵌套在函数内部),但是它们可以嵌套到其他对象声明或非内部类中,

object MyInfo: Info("submit"),IClickListener {

    override fun doClick() {
        println("MyInfo do click, $text") // Log: MyInfo do click, , submit
    }
}

fun main(args: Array<String>) {

    MyInfo.doClick()
}
//当对象声明在另一个类的内部时,这个类的实例并不能直接访问对象申明内部,而只能通过类名来访问,同样该对象也不能直接访问到外部类的方法和变量
class Site {
    var name = "菜鸟教程"
    object DeskTop{
        var url = "www.runoob.com"
        fun showName(){
            print{"desk legs $name"} // 错误,不能访问到外部类的方法和变量
        }
    }
}
fun main(args: Array<String>) {
    var site = Site()
    site.DeskTop.url // 错误,不能通过外部类的实例访问到该对象
    Site.DeskTop.url // 正确
}

伴随(生)对象:相当于静态内部类+该类的静态属性,所在的类被加载,伴生对象被初始化

class Books(var name: String, val page: Int) {
    companion object ComBooks{
        val a : Int = 10
        fun doNote() {
            println("do note")
        }
    }
}

fun main(args: Array<String>) {
    Books.ComBooks.doNote()

    println("Book.a = ${Books.ComBooks.a}")

    println("-------------")

    Books.doNote()

}

// Log
do note
Book.a = 10
-------------
do note
//伴随对象的成员可以通过类名做限定词直接使用:
class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}
val instance = MyClass.create()
//在使用了 companion 关键字时,伴随对象的名字可以省略:
class MyClass {
    companion object {

    }
}
//尽管伴随对象的成员很像其它语言中的静态成员,但在运行时它们任然是真正类的成员实例,比如可以实现接口:
interface Factory<T> {
    fun create(): T
}

class MyClass {
    companion object : Factory<MyClass> {
        override fun create(): MyClass = MyClass()
    }
}
//如果你在 JVM 上使用 @JvmStatic 注解,你可以有多个伴随对象生成为真实的静态方法和属性

2、属性字段相关

备用字段:Kotlin中不能有field,但在自定义getter/setter的时候需要直接访问属性而不是又通过getter/settter来取值赋值(循环调用)。Kotlin自动提供一个备用字段(field),通过它可以直接访问属性,没有使用备用字段时不生成备用字段(使用了setter就会生成)

 //使用field关键字
public var fieldProp = ""
    get() = field
    set(value) {
        field = value;
    }
//不生成:
val isEmpty: Boolean
    get() = this.size == 0
//生成:
val Foo.bar = 1

备用属性:功能与备用字段类似。:

private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap() // 参数类型是自动推导
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

Kotlin可以像python(@property)一样把方法变成属性调用,Kotlin是定义一个属性复写get()方法返回某个对象中其他的计算出来的值。

3、编译时常量

相当于java static finial xxx,而val 只是fInal ,一个编译时常量,一个运行时常量。使用const必须:

在kt文件中(类之外,Top-level)或在object{}中
必须是基本类型或String
必须没有自定义getter

4、代理模式

类代理:
Kotlin 在语法上支持代理 ,Derived 类可以继承 Base 接口并且指定一个对象代理它全部的公共方法:

 interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { printz(x) }
}

class Derived(b: Base) : Base by b

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}
//在 Derived 的父类列表中的 by 从句会将 b 存储在 Derived 内部对象,并且编译器会生成 Base 的所有方法并转给 b

代理属性:
所谓的委托属性,就是对其属性值的操作不再依赖于其自身的getter()/setter()方法,是将其托付给一个代理类,从而每个使用类中的该属性可以通过代理类统一管理,再也不用在每个类中,对其声明重复的操作方法。语法:

val/var <property name>: <Type> by <expression>
//var/val:属性类型(可变/只读)
//name:属性名称
//Type:属性的数据类型
//expression:代理类

使用场景:

延迟加载属性(lazy property): 属性值只在初次访问时才会计算
可观察属性(observable property): 属性发生变化时, 可以向监听器发送通知
将多个属性保存在一个 map 内, 而不是保存在多个独立的域内

Kotlin标准库中已实现的代理:

延迟加载(Lazy):lazy()是一个函数, 接受一个Lambda表达式作为参数, 返回一个Lazy类型的实例,这个实例可以作为一个委托, 实现延迟加载属性(lazy property): 第一次调用 get() 时, 将会执行 lazy() 函数受到的Lambda 表达式,然后会记住这次执行的结果, 以后所有对 get() 的调用都只会简单地返回以前记住的结果:

val no: Int by lazy {
    200
}

val c = 200

fun main(args: Array<String>) {

    val b = 200

    println(no) // Log : 200
    println(no) // Log : 200
}

注意:

var类型属性不能设置为延迟加载属性,因为在lazy中并没有setValue(…)方法
lazy操作符是线程安全的。如果在不考虑多线程问题或者想提高更多的性能,也可以使用 lazy(LazyThreadSafeMode.NONE){ … },lazy的三个参数为:

SYNCHRONIZED:锁定,用于确保只有一个线程可以初始化[Lazy]实例。
PUBLICATION:初始化函数可以在并发访问未初始化的[Lazy]实例值时调用几次,,但只有第一个返回的值将被用作[Lazy]实例的值。
NONE:没有锁用于同步对[Lazy]实例值的访问; 如果从多个线程访问实例,是线程不安全的。此模式应仅在高性能至关重要,并且[Lazy]实例被保证永远不会从多个线程初始化时使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值