【问题标题】:Kotlin: Intrinsics.areEqual infinite loop (stack overflow)Kotlin:Intrinsics.areEqual 无限循环(堆栈溢出)
【发布时间】:2017-12-15 22:42:41
【问题描述】:
java.lang.StackOverflowError
    at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:164)
    at plugin.interaction.inter.teleports.Category.equals(Category.kt)
    at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:164)
    at plugin.interaction.inter.teleports.Destination.equals(Destination.kt)

发生在两个非关系数据类之间的 .equals 比较中。

主要错误。

data class Category(val name: String, val destinations: MutableList<Destination>)

data class Destination(val category: Category, val name: String)

【问题讨论】:

  • 有趣,你能展示一下抛出错误的类和代码吗?
  • 这是因为CategoryDestination 可能具有周期相关性。
  • @holi-java 啊,这在某种意义上是真的。 Category 有一个MutableList&lt;Destination&gt;Destination 有一个Category
  • @zsmb13 添加了简化示例。

标签: kotlin stack-overflow intrinsics


【解决方案1】:

Data classes in Kotlin are just syntactic sugar for Java POJOs.

你的例子中的罪魁祸首是这个循环:

val destinations: MutableList&lt;Destination&gt; in Category &
val category: Category in Destination

您必须通过将两个变量中的任何一个移出主数据类构造函数来移除此循环。

然而,还有一个很多更大的副作用:data class Category(..)可变,这将导致它(以及在其主要构造函数中使用类别的任何其他数据类!) 在任何基于散列的集合中用作键是不安全的。更多信息请见:Are mutable hashmap keys a dangerous practice?

鉴于数据类是针对纯数据的,我建议删除data class Destination(..) 中的val category: Category,并将data class Category(..)val destinations: MutableList&lt;Destination&gt; 的类型更改为只读List&lt;Destination&gt;。为了在上述更改后打破不可变状态,您必须从 Kotlin 执行不安全强制转换或从 Java 创建类的实例。

但是,如果您绝对需要对目标中的类别进行反向引用(并且没有在 hashmaps/-sets/等中使用您的类),您可以将 Destination 设为常规类并自己实现 equals/hashCode,或者移动类脱离主构造函数。这有点棘手,但可以通过辅助构造函数来完成:

data class Destination private constructor(val name: String) {
    private lateinit var _category: Category
    val category get() = _category
    constructor(category: Category, name: String) : this(name) {
        _category = category
    }
}

【讨论】:

    【解决方案2】:

    在我的例子中,我重写了 equals 方法,例如:

    override fun equals(other: Any?): Boolean {
            // some code here
            if (other==this)
                return true
           // some code here
        }
    

    java 中的等于和 ==

    在 java 中,当我们使用 equals(例如:str1.equals(str2))时,它会检查两个对象的内容(对于自定义对象,您必须重写 equals 并检查对象的所有值,否则 Object 类的 equals 方法只是比较引用,与 ==) 相同,但如果我们使用 ==(例如:str1==str2) 运算符,它会检查两个对象的引用。


    == 在 kotlin 中

    但是在 kotlin 的情况下,当我们使用 == 运算符时,它只会检查对象的内容(数据或变量),前提是它们是数据类的对象。并且 == 运算符检查普通类的引用。

    当我们使用 == 时,它会调用 equals 方法。


    所以在我重写的 equals 方法中,当other==this 将执行时,它会再次调用eaquals 方法,这将再次调用eaquals 方法并进行无限循环。

    为了让它工作,我们需要将 == 更改为 ===(这将检查两个运算符的引用),例如:

     if (other===this)
         return true
    

    注意:.equals== 是相同的,直到我们将它们与 Float 或 双倍的。 .equals 不同意 IEEE 754 标准 浮点运算,比较 -0.0 时返回 false 0.0 而 == 和 === 返回 true

    您可以查看参考here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 2018-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多