栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Kotlin进阶学习-第四篇

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Kotlin进阶学习-第四篇

Kotlin进阶学习—第四篇

读者学习本篇文章前请先学习之前的文章

Kotlin系列已更新:

Kotlin基础学习-入门篇

Kotlin基础学习-第二篇

Kotlin进阶学习-第三篇

Kotlin进阶学习-第四篇

泛型

笔者之前写过一篇关于Java泛型的文章

Kotlin的泛型和Java的泛型有同有异,因此本篇文章只学习泛型的基础用法,基础和原理请看上面文章。

泛型类

声明如下:

class MyClass {
    
    private var value: T? = null
    
    public fun setValue(value: T) {
        this.value = value
    }
    
}

使用如下:

var myClass = MyClass()
myClass.setValue(123)

声明对象时传入Int,属性value的类型则为Int

泛型方法

声明如下:

public fun  method(param: T): T{
    return param
}

使用如下:

method(123)
限定泛型类型

有时候程序员相对泛型的类型进行限制,则需借助继承来实现

声明如下:

fun  method(param: T): T{
    return param
}

若不指定类型,T会被类型擦除为Any?,?代表可为空,Any则等价于Java的Object

改进第三篇中的build函数

在第三篇文章中,我们编写了一个StringBuilder的拓展函数build,其用法与apply一样

fun StringBuilder.build(block: StringBuilder.() -> Unit): StringBuilder {
    block()
    return this
}

上述写法中build函数只能对StringBuilder生效,若想其他类使用则需下面写法,声明顶层方法:

fun  T.bulid(block: T.() -> Unit): T {
    block()
    return this
}

这时任何对象都可使用build函数,效果与apply等价

委托

委托是一种设计模式,基本理念是:操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。

Java没有再语法层面对委托模式进行支持,而kotlin是支持的。

委托分为两种类委托和委托属性

类委托

类委托则是将一个类的具体实现委托给另一个类去完成

之前我们学习了set,如果我们想实现自己的set,借助委托模式如下:

class MySet(val helpSet: HashSet) : Set {
    override val size: Int
        get() = helpSet.size

    override fun contains(element: T) = helpSet.contains(element)

    override fun containsAll(elements: Collection) = helpSet.containsAll(elements)

    override fun isEmpty() = helpSet.isEmpty()

    override fun iterator() = helpSet.iterator()

}

MySet全部的实现都是依靠委托类HashSet去完成的,那直接调用HashSet不可以吗?可以,但是委托模式允许我们加入独有的方法,MySet则可成为一个全新的数据结构类,这也是委托模式存在的意义。

上述写法是存在弊端的,若set接口中有非常多的方法,那岂不是MySet都要实现一遍,Java中并没有提供解决方法,但Kotlin可以借助by关键字来解决上述问题

借助by,上述代码可改为:

class MySet(val helpSet: HashSet) : Set by helpSet{
    //定义自己的新方法
    fun helloWorld() = println("Hello world")
    
    //重写方法,错误示范,只是举例
    override fun isEmpty(): Boolean {
        return false;
    }

}
属性委托

类委托是将具体实现委托给另一个类去完成,委托属性则是一个属性的具体实现委托给另一个类去完成

其使用如下:

创建MyClass并声明需要委托的属性

class MyClass {
    var p by Delegate()
}

创建Delegate类,并且必须实现get和set方法

class Delegate {
    
    var propValue: Any? = null

    operator fun getValue(myClass: MyClass, prop: KProperty<*>): Any? {
        return propValue
    }

    operator fun setValue(myClass: MyClass, prop: KProperty<*>, value: Any?) {
        propValue = value
    }
}

上述的get和set,必须使用重载符operator修饰,其中都有两个参数,前一个参数为在哪个类可以使用委托,写成MyClass代表只可在MyClass中使用,第二个参数KProperty<*>是Kotlin的一个属性操作类,用于获取各种属性相关的值,当前用不到,但必须声明,<星>类似于java的,靠程序员自己去定义,只是上述演示使用星

其原理具体流程如下:当我们给p赋值时,则会调用到Delegate的setValue方法,若获取时则会调用getValue方法。

**注意:**若上述p声明为val,则不需要实现setValue方法

lazy

lazy时Kotlin提供的一种懒加载技术,使用如下:

val p by lazy {
    //初始化操作
}

只有当真正调用p是才会执行Lambda中的代码,对p进行初始化

上述学习了委托,则可对lazy的原理进行分析:

调用lazy函数会创建一个Delegate对象,在构造Delegate时可以将Lambda传给Delegate,因此在后续我们使用p,调用Delegate的getValue方法时就可以先执行Lambda再返回value。

下面仿照lazy实现一个简单的懒加载:

创建Later.kt

class Later(val block: () -> T) {
    var value: Any? = null
    
    operator fun getValue(any: Any?, prop: KProperty<*>): T {
        if (value == null) {
            value = block()
        }
        return value as T
    }
}

//顶层方法,任何地方都可以调用
fun  later(block: () -> T) = Later(block)

使用如下:

fun main() {
    val p by later {
        "abc"
    }
    println(p + "  " + 2)
}
//打印结果 abc  2

上述懒加载只是简单的实现,在开发过程还需使用内置的lazy,其内部有严谨的判空机制。

infix

在前几篇文章中学习了map的使用,其有一种初始化map的方法如下:

mapOf("A" to 1, "B" to 2)

之前没有讲解**“A” to 1**这种方式的原理,本节对to的原理进行解析:

to不是关键字,to是一个函数,“A” to 1这种写法是Kotlin提供的语法糖:infix函数,其等价于**A.to(1)**的写法

infix使用

下面实现String的startsWith(),最终使用效果类似于**“Hello World” startsWith “Hello”**

使用后infix定义一个beginsWith函数:

infix fun String.beginsWith(prefix: String) = startsWith(prefix)

使用如下:

if ("Hello World" beginsWith "Hello") {
    //处理逻辑
}

注意:infix函数只能接受一个参数。

下面再使用一个例子对容器的contains方法进行简化:

infix fun  Collection.has(element: T) = contains(element)

使用如下:

val list = listOf("a", "b", "c")
if (list has "b") {
    //处理逻辑
}
to和Pair对象原理

查看to函数的源码:

public infix fun  A.to(that: B): Pair = Pair(this, that)

在上篇文章中我们也对Pair进行了了解,其有两个属性first,second,对应key,value

public data class Pair(
    public val first: A,
    public val second: B
) : Serializable {
    ...
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/820108.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号