Kotlin对象比较注意点示例详解

目录
  • 背景
  • 原因
  • 另一个问题
  • 解决办法
  • 结论

背景

  • 现有一个StateFlow及其监听
private val stateFlow = MutableStateFlow(kotlin.Pair<String, ArrayList<String>>("abc", ArrayList()))
GlobalScope.launch {
    stateFlow.collect {
        // do something
    }
}
  • 更新ArrayList并尝试emit
GlobalScope.launch {
    stateFlow.value.second.add("test")
    stateFlow.emit(stateFlow.value)
}

实际上,collect并不会被调用

原因

MutableStateFlow真正的实现者是StateFlowImpl, emit方法代码如下:

override suspend fun emit(value: T) {
    this.value = value
}

查看value的set方法:

public override var value: T
    get() = NULL.unbox(_state.value)
    set(value) { updateState(null, value ?: NULL) }
private fun updateState(expectedState: Any?, newState: Any): Boolean {
    var curSequence = 0
    var curSlots: Array<StateFlowSlot?>? = this.slots // benign race, we will not use it
    synchronized(this) {
        val oldState = _state.value
        if (expectedState != null && oldState != expectedState) return false // CAS support
        if (oldState == newState) return true // Don't do anything if value is not changing, but CAS -> true
        _state.value = newState
        curSequence = sequence
        ... 省略部分代码
    }
}

其中"if (oldState == newState) return true"因emit前后是同一个对象,导致条件为true,那么,如果emit前后不是同一个对象,即可解决这个问题?

另一个问题

emit时尝试以下代码:

GlobalScope.launch {
    stateFlow.value.apply {
        stateFlow.emit(kotlin.Pair(first, second))
    }
}

实际上,上述代码仍旧不能解决问题,因为kotlin.Pair默认重写了equals方法,查看kotlin.Pair decompiled的Java文件

public final class Pair {
    public int hashCode() {
        Object var10000 = this.first;
        int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
        Object var10001 = this.second;
        return var1 + (var10001 != null ? var10001.hashCode() : 0);
    }

    public boolean equals(@Nullable Object var1) {
        if (this != var1) {
            if (var1 instanceof Te.Pair) {
                Te.Pair var2 = (Te.Pair) var1;
                if (Intrinsics.areEqual(this.first, var2.first) && Intrinsics.areEqual(this.second, var2.second)) {
                    return true;
                }
            }
            return false;
        } else {
            return true;
        }
    }
}

其中Intrinsics.areEqual代码如下:

public static boolean areEqual(Object first, Object second) {
    return first == null ? second == null : first.equals(second);
}

故即使pair对象本身不一样,但由于kotlin默认重写了equals方法,而pair.first与pair.second是一样的,从而条件"if (oldState == newState) return true"成立

解决办法

由于StateFlow源码无法修改且是特定场景需求,故无法将判断条件改为kotlin的"===";故使用android.util.Pair或者自定义java Pair class即可

结论

kotlin class默认实现了equals方法,判断的是内容相等,而Java的class判断的是地址相等,故判断对象相等时需注意此细节,根据需求来判断地址相等(===)还是内容相等(==)

到此这篇关于Kotlin对象比较注意点的文章就介绍到这了,更多相关Kotlin对象比较注意点内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Kotlin中的面向对象(二)

    详解Kotlin中的面向对象(二) 在Kotlin中的面向对象(一)中,介绍了Kotlin类的相关操作,本文将在上文的基础上,继续介绍属性.接口等同样重要的面向对象的功能. 属性 class AttrDemo{ private var attr1 : String = ""; protected var attr2 : String = ""; public var attr3 : String = ""; var varattr : Strin

  • Kotlin基础教程之伴生对象,getter,setter,内部,局部,匿名类,可变参数

    先来看一个名为Message的类 在这个类中有一段包含在companion object中的代码,需要说一下的是,Kotlin的class并不支持static变量,所以需要使用companion object来声明static变量,其实这个platformStatic变量也不是真正的static变量,而是一个伴生对象, 这个伴生对象位于Message类中定义的一个叫做Companion的内部类中,如图: 可以看到在Kotlin中编译器自动生成类是很常见的事情,那么这个伴生对象作何理解呢? 我的理

  • Kotlin 创建接口或者抽象类的匿名对象实例

    一 ,定义接口和抽象类 interface IPerson{ //获取名字 fun getName():String //获取身份证ID fun getID():String } abstract class BaseAnimal{ abstract fun getVoice():String } 二,创建对应的匿名对象 object : IPerson { override fun getName(): String = "jason" override fun getID(): S

  • Kotlin中的对象表达式和对象声明的具体使用

    Kotlin的对象表达式与Java中的匿名内部类的主要区别:匿名内部类只能指定一个父类型,但对象表达式可以指定0~N个肤类型. 一.对象表达式 对象表达式的语法格式如下: object [: 0~N个父类型]{ //对象表达式的类体部分 } 对象表达式还有如下规则: 对象表达式不能是抽象类,因为系统在创建对象表达式时会立即创建对象.因此不允许将对象表达式定义成抽象类. 对象表达式不能定义构造器.但对象表达式可以定义初始化块,可以通过初始化块来完成构造器需要完成的事情. 对象表达式可以包含内部类,

  • Kotlin 基础教程之类、对象、接口

    Kotlin 基础教程之类.对象.接口 Kotlin中类.接口相关概念与Java一样,包括类名.属性.方法.继承等,如下示例: interface A { fun bar() fun foo() { // 可选方法体 } } class Child: A { override fun bar() { // todo } override fun foo() { super.foo() } } class 构造器 Kotlin 中的类可以有一个 主构造器, 以及一个或多个次构造器, 主构造器是类头

  • Kotlin基础教程之面向对象

    Kotlin 面向对象 这几天一直在准备考试,实在没有时间,已经过去了这么久,终于要到面向对象了! 先看看Kotlin中的类长什么样吧. 可以看到Kotlin中的类还是很普通的,大多与Java相似,比较特殊的有: 每一个构造函数都必须为每一个成员变量赋予初值. primary constructor,这个构造函数的头部紧跟在类名之后,函数体却在类中,是由init关键字包含的一个代码块,这种函数头和函数体分开的写法还是很少有的,其实这两个部分会被整合成一个构造函数,使用jd-gui反编译class

  • 详解Kotlin中的面向对象(一)

    Kotlin中的面向对象 面向对象 面向对象的含义大家应该并不陌生,通过将事物抽象成对象,大大简化了程序的开发难度.我们常用的Java.Python.C++都属于面向对象的编程语言.Kotlin和java很相似,也是一种面向对象的语言.作为Kotlin中最重要的一部分,我们可以通过了解Kotlin的OOP进而了解这门语言,本文将从类.属性.接口.对象等多个方面介绍Kotlin的面向对象的特性. 类 和大部分语言类似,Kotlin使用class作为类的关键字,当我们声明一个类时,需要通过class

  • Kotlin对象比较注意点示例详解

    目录 背景 原因 另一个问题 解决办法 结论 背景 现有一个StateFlow及其监听 private val stateFlow = MutableStateFlow(kotlin.Pair<String, ArrayList<String>>("abc", ArrayList())) GlobalScope.launch { stateFlow.collect { // do something } } 更新ArrayList并尝试emit GlobalSc

  • Kotlin协程Dispatchers原理示例详解

    目录 前置知识 demo startCoroutineCancellable intercepted()函数 DefaultScheduler中找dispatch函数 Runnable传入 Worker线程执行逻辑 小结 前置知识 Kotlin协程不是什么空中阁楼,Kotlin源代码会被编译成class字节码文件,最终会运行到虚拟机中.所以从本质上讲,Kotlin和Java是类似的,都是可以编译产生class的语言,但最终还是会受到虚拟机的限制,它们的代码最终会在虚拟机上的某个线程上被执行. 之

  • JavaScript console对象与控制台使用示例详解

    目录 1. console对象 2. console的静态方法 3. 自定义console 4. 控制台命令行API 4.1 $_ 4.2 $0-$4 4.3 $(selector) 4.4 $x(path) 4.5 inspect(obj) 4.6 keys()和values() 4.7 其它的命令 1. console对象 console对象是JavaScript的原生对象,提供了很多用于调试的方法,如console.log输出信息,console.count记录执行次数 console.l

  • 图解 Kotlin SharedFlow 缓存系统及示例详解

    目录 前言 replay extraBufferCapacity onBufferOverflow SharedFlow Buffer 前言 Kotlin 为我们提供了两种创建“热流”的工具:StateFlow 和 SharedFlow.StateFlow 经常被用来替代 LiveData 充当架构组件使用,所以大家相对熟悉.其实 StateFlow 只是 SharedFlow 的一种特化形式,SharedFlow 的功能更强大.使用场景更多,这得益于其自带的缓存系统,本文用图解的方式,带大家更

  • kotlin android extensions 插件实现示例详解

    目录 前言 原理浅析 总体结构 源码分析 插件入口 配置编译器插件传参 编译器插件接收参数 注册各种Extension IrGenerationExtension ExpressionCodegenExtension StorageComponentContainerContributor ClassBuilderInterceptorExtension PackageFragmentProviderExtension 总结 前言 kotlin-android-extensions 插件是 Ko

  • java教程之对象序列化使用基础示例详解

    这个过程也可以通过网络实现,可以先在Windows机器上创建一个对象,对其序列化,然后通过网络发给一台Unix机器,然后在那里准确无误地重新"装配".像RMI.Socket.JMS.EJB它们中的一种,彼此为什么能够传递Java对象,当然都是对象序列化机制的功劳. Java对象序列化机制一般来讲有两种用途: Java的JavaBeans: Bean的状态信息通常是在设计时配置的,Bean的状态信息必须被存起来,以便当程序运行时能恢复这些状态信息,这需要将对象的状态保存到文件中,而后能够

  • Kotlin的枚举与异常示例详解

    一.kotlin中枚举的定义 枚举需要用到两个关键字 enum class,譬如这样 enum class Color(val r: Int,val g: Int,val b: Int){ //彩虹色也是一个典故:韦克菲尔德战役 RED(255,0,0),ORANGE(255,165,0),YELLOW(255,255,0), GREEN(0,255,0),BLUE(0,0,255),INDIGO(75,0,130),VIOLET(238,130,238); fun rgb() = (r * 2

  • Android开发Kotlin实现圆弧计步器示例详解

    目录 效果图 定义控件的样式 自定义StepView 绘制文本坐标 Android获取中线到基线距离 效果图 定义控件的样式 看完效果后,我们先定义控件的样式 <!-- 自定义View的名字 StepView --> <!-- name 属性名称 format 格式 string 文字 color 颜色 dimension 字体大小 integer 数字 reference 资源或者颜色 --> <declare-styleable name="StepView&q

  • Kotlin编程条件控制示例详解

    目录 本文总览 1. When 表达式 2. If 表达式 总结 本文总览 本篇来看看 Kotlin的条件控制,这一节知识点 建议与Java中的条件结构类比,会很好理解并记住. 1. When 表达式 在 Kotlin 用 when 来定义多个分支的条件表达式.Kotlin中这个语法与 java 中的 switch 语句非常类似.代码块的执行就是将参数与所有的分⽀条件顺序⽐较,直到满⾜某个分⽀条件:(示例 ) when (x) { 1 -> print("x == 1") 2 -

  • Kotlin编程循环控制示例详解

    目录 本文总览 1. While循环 2. For循环 3. break和continue 3.1 break语句 3.2 continue语句 总结 本文总览 本篇来学习Kotlin循环结构的知识 1. While循环 while循环用于重复迭代代码块,只要给定条件为 true就会执行一次循环代码块.若条件为 false,则直接跳过循环代码块执行后面代码. while (x > 0) { x-- } // 当条件 x>0 成立,x 就会减一 do-while循环 与 while循环相类似,也

随机推荐