美文网首页
Kotlin中的引用

Kotlin中的引用

作者: 盛世光阴 | 来源:发表于2021-06-10 01:08 被阅读0次

前言

Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言

img.jpg

引用

Kotlin 中的引用有不同的使用方式有 函数引用、属性引用、类引用、构造函数引用、扩展函数引用、绑定引用等

函数引用

可以通过::引用其他函数作为高阶函数的参数

  • 对象::函数名
  • 类名::函数名

将函数转换为lambda的格式
首先随便定义一个函数

class Test {

  fun print(str: String) {

  }

}

这个函数有一个String参数,无返回值,将他转换为lambda表达式的形态就是
(String) -> Unit
任何函数都可以转换为lambda的形态
(String) -> Int
(String,String) -> String

如何使用函数引用
定义一个高阶函数 test

class Test {
    fun print(str: String) {
        print(str)
    }

    fun test(value:(String) -> Unit){
        value("test")
    }
}

当我们调用的时候需要个给value传入一个参数为String,返回值为Unit的函数,我们一般可以直接在调用处声明一个对应的lambda,也可以引用符合此函数类型的其他函数

fun main(){
    test {

    }
    test(this::print) //函数引用
}

这种写法编译之后就会变成

fun print(str: String) {
    print(str)
}
fun test(value:(String) -> Unit){
    value("test")
}
编译后
public final void print(String str){
    print(str)
}
public final void test(@NotNull Function1 call) {

}

函数引用位置

test(this::print)
编译后
test1(object : Function1<Any?, Any?>(this) {
    operator fun invoke(p1: String) { //根据所引用的函数所自动生成的函数
        (this.receiver as TestReference).test(p1)
    }
})

函数引用也可以直接执行,因为引用本质上也是一个函数

class Account {

    fun test() {}

    fun call() {
        val a1 = Account::test
        a1(Account())
        val a2 = Account()::test
        a2()
    }
}

函数引用的使用场景
引用现有的函数实现,不用再创建自己的实现

help.setOnClickListener { }

可以将响应事件的Lambda抽离成函数,然后进行引用

btnLogin.setOnClickListener(::onClick) //this可以省略

fun onClick(view:View){}

属性引用

属性引用与函数引用用法相同,只不过目标是属性

class LoginActivity : DaggerAppCompatActivity() {

    val test = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.e("mike", "${this::test}")
        Log.e("mike", ::test.name)
        Log.e("mike", "${::test.get()}")
    }
    
}
mike: val com.mike.loginmvvm.login.ui.LoginActivity.test: kotlin.Int
mike: test
mike: 1

属性引用这里主要是编译生成用到了KProperty相关,this::test被编译成了一个持有引用对象this的KProperty0对象

this::test 
编译后
KProperty0 t1 = new TestReference$call$t1$1((TestReference)this)

再看KProperty0的声明,在上面的案例中他也可以当做函数() -> Int使用

public actual interface KProperty0<out R> : KProperty<R>, () -> R {}
fun test(value:()->Int){}
test(this::test)

属性引用的使用

String::length
编译后
KProperty1 var10000 = TestReference$call$1.INSTANCE;

会生成一个KProperty1 对象

public actual interface KProperty1<T, out R> : KProperty<R>, (T) -> R {}

String::length等价于

(Strring) ->{ str
   returm str.length
}

所以可以写为

listOf<String>("1", "12", "123").map(String::length)
输出[1,2,3]

类引用

获取KClass以及Class对象,是我们使用最多的引用方式

  • 类名::class
  • 类名::class.java
  • 对象::class
  • 对象::class.java

构造函数引用

引用类的构造函数

class Test {
    constructor() {}

    constructor(str: String) {}

    fun test1(value: () -> Test) {}

    fun test2(value: (String) -> Test) {}

    fun call() {
        test1(::Test) //引用构造函数 constructor() {}
        test2(::Test) //引用构造函数 constructor(str: String) {}
    }
}

可以引用构造函数,作为函数的入参,引用哪个构造函数取决于函数的Lambda样式

构造函数引用的使用
进行数据转换中,对象元素的映射创建

class Person(val name: String, val age: Int) {
    constructor(map: Pair<String, Int>) : this(map.first, map.second)
}
//引用构造函数,进行数据转换
listOf("张三" to 18, "李四" to 19, "王五" to 20, "Mike" to 21).map(::Person)

扩展引用

扩展函数(属性)也可以被引用

  • 类名::扩展函数(属性)名
  • 对象::扩展函数(属性)名
fun TextView.person(person: Person) {
    text = if (person.name.isEmpty()) "" else person.name
}

fun call(textView: TextView){
    val per = TextView::person
    per(textView,Person("",1))
    val per1 =  textView::person
    per1(Person("",1))
}
val bindPerson:TextView.(Person) ->Unit = TextView::person

isInitialized 扩展属性判断成员是否已经初始化
被lateinit修饰的变量需要在使用时做判断,判断是否已经初始化,未初始化使用将会抛出异常

lateinit var data:Person

需要使用到 isInitialized去进行判断,先看下其定义

/**
 * Returns `true` if this lateinit property has been assigned a value, and `false` otherwise.
 *
 * Cannot be used in an inline function, to avoid binary compatibility issues.
 */
inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean
    get() = throw NotImplementedError("Implementation is intrinsic"
  • 首先它不能使用到inline function
  • 它是KProperty0的扩展属性,所以需要KProperty0对象才能调用
  • 返回值此属性是否已经初始化

拿到data的引用,也就是KProperty0,然后调用isInitialized

if(::data.isInitialized){
            
}

欢迎关注Mike的简书

Android 知识整理

相关文章

  • Kotlin中常量和静态方法

    常量 Java代码: Kotlin中: 引用常量(这里的引用只针对于java引用kotlin代码) TestEnt...

  • Kotlin中的引用

    前言 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift...

  • Kotlin笔记

    一、Kotlin基础 1.1 变量 在Kotlin中变量分为可变引用var和不可变引用val,val对应的是jav...

  • kotlin-stdlib-jre7 is deprecated

    可能kotlin中的一个引用被删了

  • 26.Kotlin与Java互操作

    Kotlin与Java互操作 在Kotlin中操作Java 示例代码:Person类 在Java中,所有引用都可能...

  • Kotlin函数

    1.函数引用 kotlin中函数引用跟c++中的方法指针很相似,函数引用可以像其他类型的引用一样作为方法的参数和返...

  • kotlin中的函数引用详解

    抛砖引玉 做C/C++开发的同学肯定熟悉域作用符(::),这个符号在kotlin中可以获取函数的引用。函数引用是k...

  • Kotlin 空安全

    可空类型与非空类型 在 Kotlin 中,类型区分引用可以为 null (可空引用),或不能为 null(非空引用...

  • Kotlin反射

    Kotlin把函数和属性当成“一等公民”,并可通过反射直接获取函数、属性的引用。 一、类引用 Kotlin的类引用...

  • 引用?弱引用和软引用?kotlin中咋玩?

    很多东西往往只知道怎么用,却不知道何时用。 Java中有四种引用,随便一查都是文章,这些内容大体都能看明白,但细细...

网友评论

      本文标题:Kotlin中的引用

      本文链接:https://www.haomeiwen.com/subject/ycdfeltx.html