IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【Android进阶】Kotlin笔记 -> 正文阅读

[移动开发]【Android进阶】Kotlin笔记

Sealed Class 密封类
如果想对能够创建出的子类做限制,可以使用密封类。

下面一个例子是没有使用密封类的:

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(expr: Expr): Int {
    return when(expr){
        is Sum -> eval(expr.left) + eval(expr.right)
        is Num -> expr.value
        else -> throw IllegalArgumentException("Unknown Expression")
    }
}

这类似于只支持加法的抽象语法树,Expr代表一个表达式,也就是语法树里的一个节点,同时Num代表数字节点,它只可能是叶子,Sum代表加法节点,不可能是叶子。

现在如果我们要实现eval函数来计算抽象语法树的最终结果,我们发现,始终需要一个else来收尾,因为Expr可能还有其他实现类,可能既不是Sum又不是Num,尽管代码里根本没有其他实现类。

密封类能解决这个问题。

sealed class Expr {
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
}


fun eval(expr: Expr): Int {
    return when(expr){
        is Expr.Sum -> eval(expr.left) + eval(expr.right)
        is Expr.Num -> expr.value
    }
}

密封类表明了该类不可能有除了Num和Sum之外的其他子类,所以编译器可以发现我们when中的代码是无懈可击的,自然不用一个额外的else。

类委托
Java中有一套设计模式就是委托模式,就是指编写一个类,但它不提供实现,所有的功能都会委托给另一个类实现,在必要的时候对类进行增强。Java后面的代理、动态代理技术全部都是基于委托实现的,可以说它是Java世界的一个支柱。

Kotlin默认支持委托,不像Java,要么用IDE生成一大堆代码,要么在编译期使用其他动态代理工具生成,Kotlin默认提供了by关键字。

下面的类继承自MutableCollection,但它完全不存储数据,而是通过by委托给innerSet。

class CountingSet<T> (
    val innerSet: MutableCollection<T> = HashSet<T>()
) : MutableCollection<T> by innerSet{
    var objectsAdded = 0


    override fun add(element: T): Boolean {
        objectsAdded++
        return innerSet.add(element)
    }

    override fun addAll(elements: Collection<T>): Boolean {
        objectsAdded += elements.size
        return innerSet.addAll(elements)
    }

}



fun main(){
    val set = CountingSet<Int>()
    set.add(10)
    set.addAll(listOf(1,2,4,15,5,3))
    set.remove(10)
    println(set.objectsAdded)
}

比较常用的就是委托类作为构造器参数传入,Java中比较常见的就是基于委托的IO流,我们经常这样写:

new BufferedInputStream(new FileInputStream(...));

这里BufferedInputStream并不会自己实现InputStream的读取功能,而是委托给FileInputStream并对它的功能进行增强(通过建立缓冲区)。

我们上面编写的类也是,你可以调用CountingSet传入不同的Collection实现,不同的是我们提供了一个默认值。

除了使用构造器参数,还可以直接新建一个类委托,因为有时候我们就想让它委托同一个类,不想让用户自己抉择。

class MySet<T> () : 
    MutableCollection<T> by HashSet<T>(){

}

属性委托
Jetpack Compose中有一个记录状态并自动更新UI的东西,就是var value by remember,这种监测数据更新并自动刷新UI的东西在如今数据驱动的框架中并不少见。Jetpack Compose就是通过属性委托来实现的数据监测。

class Remember{
    lateinit var name: String
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
//        return name
        return name
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>,value: String) {
//        name = value
        println("${property.name} is changed!!!")
        name = value
    }

}

fun main(){
    var name: String by Remember()
    name = "ASDFASDF"
    println(name)
}

/*
name is changed!!!
ASDFASDF
*/

被委托的类应该实现一个getValue和setValue方法,委托方的变量不再存储值,而是由被委托的类提供存储功能。

我们接下来编写一个懒加载的属性委托,就是第一次访问属性时才为属性赋值

class LazyDelegate<T>(private val compute: ()->T){
    var t: T? = null
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        if (t == null) t = compute()
        return t!!
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>,value: T) {
        t = value
    }
}
fun <T> lazy(compute: ()->T) = LazyDelegate<T>(compute)

fun main(){
    var name: String by lazy {
        "HelloWorld"
    }

    println(name)
}

这一次我们提供了一个lazy方法,Lazy方法会返回我们的委托人LazyDelegate,因为Kotlin官方就为一些自带的委托封装了方法,可能是Kotlin社区惯用的编码规范,确实,这样好看一些,而且Jetpack Compose中的remember实际上也是这样写的。

然后,我们还运用了泛型和lambda表达式,lambda用于返回一个值,一般使用懒加载的时候,这个lambda表达式都会是一个很复杂并且可能并不常用的运算,所以这样如果这个值如果没被需要,懒加载就不会执行。泛型用于支持全部类型的值。

伴生对象
Java中经常会使用静态工厂方法来构造对象,这是因为静态工厂方法比构造器更加适用于处理那些很多属性可以不在构造时提供的类。静态工厂方法更加具有可读性。Kotlin根本没有静态这一说,Kotlin代替静态的办法一个是object,一个是顶层函数。但这俩都不适用于静态工厂,因为静态工厂经常要访问类中的私有成员。

伴生对象是用来干这些的。

class Person private constructor(
    name: String?, 
    age: Int?, 
    address: String?
){
    companion object {
        fun fromNameAndAge(name: String, age: Int): Person = Person(name,age,null)
        fun fromName(name: String): Person = Person(name,null,null)
        fun fromNameAndAddress(name: String, address: String): Person = Person("Lucy",null,address)
        fun newPerson(name: String, age: Int, address: String): Person = Person(name,age,address)
    }
}

fun main(){
    Person.fromNameAndAge("Lucy",12)
}

这对于Builder模式同样适用,对于绝大多数需要和类中私有成员进行交互的地方,都适用。

但是,别忘了Kotlin中的命名参数,上面的例子本可以用命名参数更加方便的解决。

class Person constructor(
    name: String, 
    age: Int? = null, 
    address: String? = null
)

fun main(){
    Person(name = "Lucy", age = 12)
}

当然伴生对象可以命名

class Person constructor(
    name: String, 
    age: Int? = null, 
    address: String? = null
){
    companion object Loader{
        fun fromJson(json: String): Person{ ... }
    }
}

fun main(){
    Person.Loader.fromJson()
}

伴生对象也可以有扩展函数,这是因为像上面的Loader这种伴生对象和类中的逻辑关系不大,分离到外部可以实现关注点分离。

class Person constructor(
    name: String, 
    age: Int? = null, 
    address: String? = null
){
    companion object Loader{}
}

fun Person.Loader.fromJson(json: String): Person {
    ...
}

fun main(){
    Person.Loader.fromJson()
}

如果是没有名字的伴生对象,也可以

fun Person.Companion.fromJson(json: String): Person{
    ...
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-12 00:07:14  更:2022-01-12 00:08:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:56:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码