Kotlin 基础篇

Kotlin 的文章已经很多了,这边就不做过多介绍了。说说项目中常用的,以及一些个人的理解吧。顺道复习复习

kotlin 基础操作符

基础这一块就不提了,用过的都熟悉。

当然非空断言公司是禁用的

但是有一个疑问点,既然任何地方都可以用空安全,那么 lateinit 这个关键字又有什么作用?不知道大家有没有想过这个原因?

其实看过转换后的代码就很容易知道了,示例代码(手打的不一定准确)

kotlin 复制代码
var user:User? = null

fun test(){
    user?.name = "1"
}

转换后的代码就是这样

java 复制代码
User user;

fun test(){
    if(user != null){
        user.name = "1"
    }
}

就会多出来一个空判断,而 lateinit 就没有这个空判断(代码就不写了)。相比来说 lateinit 性能上会好一点。这也是 lateinit 存在的原因。在你确保对象不会为空的情况下可以使用 lateinit 优化性能。

Kotlin 常用操作符 let、run、apply、also、with

kotlin 复制代码
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}


@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

源码分析

let: 是把自己以参数的形式回调出去给使用,并且返回 block (及最后一行),本人一般用于需要传递该对象的时候

run: 是以调用者本身的一个扩展函数的形式执行,并且返回 block (及最后一行),本人一般用于对象执行操作

apply: 是以调用者本身的一个扩展函数的形式执行,并且返回调用者本身,本人一般用于对象创建时赋值

also: 是把自己以参数的形式回调出去给 block 使用,并且返回调用者本身,本人一般用于附加操作

with: 是以第一个参数的一个扩展函数的形式执行,并且返回第一个参数 block (及最后一行),本人一般用于设置时间监听时使用

Kotlin 关键字

inline 关键字、oninline 关键字、crossinline 关键字

inline:用于修饰函数,将函数的实现内联到调用处,可以减少函数调用的开销。

noinline:用于修饰函数参数,表示该参数不会被内联,默认情况下,Kotlin 编译器会将具有 lambda 表达式作为参数的函数进行内联优化,但使用 noinline 关键字可以禁止内联。

crossinline:用于修饰函数参数,表示该参数必须被内联,但是不允许使用 return 语句从函数中返回。(面试时候这个玩意儿问题比较多)

详细的可以看这边文章讲的挺好的 Kotlin inline noinline crossinline 解答

reified

reified:用于修饰泛型类型参数,在运行时获取类型信息。

这个关键字也是面试中常问到的一个并且会提起 java 中类型擦除概念,那么 reifiedjava 类型擦除 有啥关联?

java 类型擦除:在 Java 中,类型擦除(Type Erasure)是指在编译时期,泛型类型信息会被擦除或转换为原始类型。这是由于 Java 泛型的实现方式------类型擦除机制。

Java 的泛型是在 JDK 5 中引入的,它允许我们在编写代码时使用参数化类型,以提高代码的类型安全性和重用性。然而,在编译时,Java 编译器会将泛型类型擦除为其原始类型。

类型擦除的主要目的是为了兼容 Java 泛型的向后兼容性。由于 Java 泛型是在 JDK 5 之后引入的,为了保持与旧版本的 Java 代码相互操作的能力,编译器会将泛型类型擦除为非泛型的形式。

例如,对于一个泛型类 List<T>,编译器会将其中的泛型类型 T 擦除为其上界或者 Object 类型。也就是说,对于编译器来说,List<String>List<Integer> 都会被擦除成 List<Object>

reified 关键字:在 Kotlin 中,使用 reified 关键字可以获取泛型的具体类型信息。

它主要用于内联函数和泛型函数中。通过使用 reified 关键字,我们可以在函数体内部获取泛型的实际类型,并对其进行操作,而不会受到类型擦除的限制。这使得在运行时可以操作泛型的具体类型。

by 关键字

Kotlin 中,什么是委托模式(Delegation Pattern)?如何使用 by 关键字实现属性委托?

委托模式是一种设计模式,其中一个对象(被委托对象)将其某些职责委托给另一个对象(委托对象)。在 Kotlin 中,by 关键字用于实现属性委托。通过使用 by 关键字,我们可以将属性的访问和修改操作委托给另一个对象。

kotlin 复制代码
// 假设我们有一个 `User` 类,它有一个属性 `name`,我们希望在每次设置 `name` 属性时打印日志。
// 我们可以使用 `by` 关键字来实现属性委托,将属性的访问和修改操作委托给另一个对象。

class Logger {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("Getting ${property.name}")
        return "John Doe"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("Setting ${property.name} to $value")
    }
}

class User {
    var name: String by Logger()
}

// 在上述示例中,我们定义了一个 `Logger` 类,它包含两个方法 `getValue()` 和 `setValue()`,分别用于获取属性值和设置属性值。
// 当我们通过 `User` 对象访问或修改 `name` 属性时,实际上是通过 `Logger` 对象来完成的。

// 例如:
fun main() {
    val user = User()
    println(user.name)     // 输出:Getting name  John Doe
    user.name = "Alice"    // 输出:Setting name to Alice
    println(user.name)     // 输出:Getting name  John Doe
}
// 通过使用 `by` 关键字和属性委托,我们可以在每次访问或修改属性时执行额外的逻辑,例如打印日志。
// 这种方式使得代码更加模块化和可重用,同时保持了类的简洁性和可读性。

对了差点忘了 by 还有个好用的地方

kotlin 复制代码
class DotMapHelper @JvmOverloads constructor(hashMap: HashMap<String, Any?> = hashMapOf()) :
    BaseDotMapHelper<DotMapHelper>(hashMap) {
    var moduleId: String? by hashMap.withDefault { null }
    var modulePosition: Int? by hashMap.withDefault { null }
    var position: Int? by hashMap.withDefault { null }
    var type: Int? by hashMap.withDefault { null }
    var elementId: Long? by hashMap.withDefault { null }
    var direction: Int? by hashMap.withDefault { null }
    var url: String? by hashMap.withDefault { null }
}

个人感觉在传参上贼好用,例如埋点的情况。

out 关键字

Kotlin 中,outin 是用来修饰类型参数的关键字,用于定义泛型类和泛型函数的类型约束。

out:用于协变(covariant)类型参数。它允许我们将子类型作为类型参数传递给泛型类或泛型函数。在使用 out 修饰类型参数时,只能将该类型参数作为输出(返回值)类型,不能用于输入(方法参数)类型。换句话说,我们可以从泛型对象中获取数据,但不能将数据存储到泛型对象中。

源码中 out 关键字:

  • List<out T>List 是一个只读接口,使用 out 关键字使其具有协变性。这意味着如果 BA 的子类型,那么 List<B>List<A> 的子类型。这使得我们可以安全地将子类型的列表分配给父类型的列表。

  • Array<out T>Array 是一个固定长度的数组类,使用 out 关键字使其具有协变性。这意味着如果 BA 的子类型,那么 Array<B>Array<A> 的子类型。这使得我们可以安全地将子类型的数组分配给父类型的数组。

  • Iterable<out T>Iterable 是一个只读接口,使用 out 关键字使其具有协变性。这意味着如果 BA 的子类型,那么 Iterable<B>Iterable<A> 的子类型。这使得我们可以安全地将子类型的可迭代对象分配给父类型的可迭代对象。

in 关键字

in:用于逆变(contravariant)类型参数。它允许我们将超类型作为类型参数传递给泛型类或泛型函数。在使用 in 修饰类型参数时,只能将该类型参数作为输入(方法参数)类型,不能用于输出(返回值)类型。换句话说,我们可以将数据存储到泛型对象中,但不能从泛型对象中获取数据。

源码中 in 关键字

  • Consumer<in T>Consumer 是一个接口,使用 in 关键字使其具有逆变性。这意味着如果 BA 的超类型,那么 Consumer<A>Consumer<B> 的超类型。这使得我们可以安全地将超类型的消费者分配给子类型的消费者。

  • Comparable<in T>Comparable 是一个接口,使用 in 关键字使其具有逆变性。这意味着如果 BA 的超类型,那么 Comparable<A>Comparable<B> 的超类型。这使得我们可以安全地将超类型的可比较对象传递给子类型的可比较对象。

operator

这个本人用的很少,有兴趣的可以自行了解。

打完收工不写了,下班铁子们。加油!!!

2023.8.9 21:49

相关推荐
沐言人生2 小时前
Android10 Framework—Init进程-9.服务端属性值初始化
android·android studio·android jetpack
追光天使3 小时前
【Mac】和【安卓手机】 通过有线方式实现投屏
android·macos·智能手机·投屏·有线
小雨cc5566ru3 小时前
uniapp+Android智慧居家养老服务平台 0fjae微信小程序
android·微信小程序·uni-app
一切皆是定数4 小时前
Android车载——VehicleHal初始化(Android 11)
android·gitee
一切皆是定数4 小时前
Android车载——VehicleHal运行流程(Android 11)
android
problc4 小时前
Android 组件化利器:WMRouter 与 DRouter 的选择与实践
android·java
图王大胜5 小时前
Android SystemUI组件(11)SystemUIVisibility解读
android·framework·systemui·visibility
服装学院的IT男9 小时前
【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
android
Arms2069 小时前
android 全面屏最底部栏沉浸式
android
服装学院的IT男9 小时前
【Android 源码分析】Activity生命周期之onStop-1
android