Kotlin 中的奇怪值比较问题,“===”返回 true,但“==”返回 false

Strange value comparison issue in Kotlin, "===" returns true but "==" returns false

提问人:Xiaoyu Yu 提问时间:7/13/2021 更新时间:5/10/2022 访问量:571

问:

我在 Kotlin 中遇到了一个非常奇怪的值比较问题,我无法解释,以下代码打印 false

data class Foo (
    val a: Byte
)
fun main() {
    val NUM: Byte = 1
    var m: Foo? = Foo(NUM)
    println(m?.a == NUM)
}

但是,如果我把最后一行改成

println(m?.a === NUM)

println(m!!.a == NUM)

它打印的是真的,我很困惑,有人可以帮忙解释吗?谢谢。

Android Kotlin 等于 平等

评论

0赞 Matt 7/13/2021
我无法在 Android Studio kotlin 暂存文件中重现此问题。这三个打印语句对我来说都是正确的。
0赞 Tenfour04 7/13/2021
我想你错了。您的原始代码也应打印 true。旁注...标识相等运算符通常对数字没有用,因为 Number 类没有稳定的标识。===
0赞 Xiaoyu Yu 7/13/2021
有趣的是,对我来说,第一种情况在 Android Studio 中打印 false,也是在 kotlin 游乐场中:play.kotlinlang.org/...,你能试试@Matt吗,@Tenfour04?
1赞 broot 7/13/2021
哦,这很有趣。所以这似乎是 1.5.20 (?) 中引入的一个错误。人们无法在本地重现它的原因可能是因为他们没有使用最新的 Kotlin 版本。我可以用 1.5.20 重现它。
1赞 Dominik 7/13/2021
我同意你的看法 - 这似乎是 1.5.20 中的一个错误。我在 jetbrains 上打开了一个问题:youtrack.jetbrains.com/issue/KT-47717。让我们看看:)会发生什么

答:

10赞 Dominik 7/13/2021 #1

该问题仅出现在版本 1.5.20 中,而 1.5.10 不受影响。

这似乎是较新的 kotlin 编译器版本中的一个问题。

用一些字节码,我们可以解释问题(被调用,被调用)。data classBlahfuncblah

这是用 1.5.10 编译的字节码,返回 - 一切似乎都很好。我们正在做一个不等于两个数字的基元,它返回(正确的,因为是)。Trueprintln(m?.a == NUM)False1 != 1False

Compiled from "WtfTest.kt"
public final class de.sfxr.WtfTest {
  public de.sfxr.WtfTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final void blah();
    Code:
       0: iconst_1
       1: istore_1
       2: new           #14                 // class de/sfxr/Blah
       5: dup
       6: iload_1
       7: invokespecial #17                 // Method de/sfxr/Blah."<init>":(B)V
      10: astore_2
      11: aload_2
      12: astore_3
      13: aload_3
      14: invokevirtual #21                 // Method de/sfxr/Blah.getA:()B
      17: iload_1
      18: istore_3
      19: iload_3
      // PRIMITIVE NOT EQUALS => False
      20: if_icmpne     27                  
      23: iconst_1
      24: goto          28
      27: iconst_0
      28: istore_3
      29: iconst_0
      30: istore        4
      32: getstatic     #27                 // Field java/lang/System.out:Ljava/io/PrintStream;
      35: iload_3
      36: invokevirtual #33                 // Method java/io/PrintStream.println:(Z)V
      39: return
}

但是,在 V1.5.20 中,字节码指示在装有内容的装箱和装有内容的装箱上使用 JVM 进行对象比较,这将返回 ,因为它使用 on 。这就是此问题的原因。在这一点上,编译器开发人员肯定想要一个。Intrinsics.areEqualInteger1Byte1FalseequalsByteTrue

但为什么这被评估为错误?下面是 的描述片段:“当且仅当参数不为 null 并且是包含与此对象相同的字节值的 Byte 对象时,结果为真。Byte.equals

...以及用于解释的字节码:

Compiled from "WtfTest.kt"
public final class de.sfxr.WtfTest {
  public de.sfxr.WtfTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final void blah();
    Code:
       0: iconst_1
       1: istore_1
       2: new           #14                 // class de/sfxr/Blah
       5: dup
       6: iload_1
       7: invokespecial #17                 // Method de/sfxr/Blah."<init>":(B)V
      10: astore_2
      11: aload_2
      12: astore_3
      13: aload_3
      14: invokevirtual #21                 // Method de/sfxr/Blah.getA:()B
      17: invokestatic  #27                 // Method java/lang/Byte.valueOf:(B)Ljava/lang/Byte;
      20: iload_1
      21: invokestatic  #32                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      // OBJECT COMPARISON VIA JVM ON BOXED BYTE(1) AND BOXED INT(1) => False
      24: invokestatic  #38                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z    
      27: istore_3
      28: iconst_0
      29: istore        4
      31: getstatic     #44                 // Field java/lang/System.out:Ljava/io/PrintStream;
      34: iload_3
      35: invokevirtual #50                 // Method java/io/PrintStream.println:(Z)V
      38: return
}

更新

jetbrains 的家伙用“这绝对是一个错误”和优先专业评论了 https://youtrack.jetbrains.com/issue/KT-47717 发出的票证。

评论

0赞 Simulant 7/13/2021
值得为它提交错误票证吗?youtrack.jetbrains.com/issues/KT
1赞 Dominik 7/13/2021
@Simulant已经完成了 youtrack.jetbrains.com/issue/KT-47717