java - hashCode() 应该返回对象的唯一 ID

标签 java kotlin hashcode

在我的 Kotlin/Java 项目中,我编写了一些继承抽象类 BaseItem 的模型类:

/**
 * All data model classes should implement this
 */
abstract class BaseItem {

    /**
     * A unique integer identifier used to represent the data item in the database.
     */
    abstract val id: Int

    override fun equals(other: Any?) = (other is BaseItem) && id == other.id

}

这些模型类将用于表示数据库中的数据。在数据库中,有一个 ID 列,其中包含唯一的整数标识符。

因此,当我使用模型类时,可以保证每个模型类的 id 属性都是唯一的。

阅读本文后,hashCode() 的 Java 规范:

  • Whenever it is invoked on the same object more than once during an execution of an application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

我的问题是:

hashCode() 中返回此唯一标识符是一个好的做法吗?

注意:我知道在 Kotlin 中,我们可以使用 data classes以便编译器自动派生预定义成员,例如 equals()hashCode()toString() 等,但 abstract 类不能是 data 类。 (但是,我可以创建 BaseItem data 类的子类 - 我不确定这是否是该用例的更好选择)。

最佳答案

由于您的抽象BaseClass用于数据类(也称为值类),因此应将equalshashCode定义为abstract 并强制执行的具体类来实现它们。例如:

abstract class BaseItem {
    abstract val id: Int
    abstract override fun equals(other: Any?): Boolean
    abstract override fun hashCode(): Int
}

data class Person(override val id: Int, val name: String) : BaseItem()

data class Product(
        override val id: Int,
        val name: String,
        val cost: BigDecimal
) : BaseItem()

在基类中实现这些函数而不是在具体子类中重写它们可能会导致违反equals & hashCode契约(Contract)。

如果不强制子类实现equals/hashCode,下面是对称性违规的示例:

abstract class BaseItem {
    abstract val id: Int
    override fun equals(other: Any?) = (other is BaseItem) && id == other.id
    override fun hashCode() = id
}

class Person(override val id: Int, val name: String) : BaseItem() {
    override fun equals(other: Any?): Boolean {
        return (other is Person) && id == other.id && name == other.name
    }

    override fun hashCode() = 31 * (31 + id.hashCode()) + name.hashCode()
}

class Product(
        override val id: Int,
        val name: String,
        val cost: BigDecimal
) : BaseItem()

fun main(args: Array<String>) {
    val baseItem1: BaseItem = Person(1, "Oliver")
    val baseItem2: BaseItem = Product(1, "grease", BigDecimal.TEN)
    println(baseItem1 == baseItem2) // false
    println(baseItem2 == baseItem1) // true
}

如果 equals/hashCode 根据其约定实现,则两个相等检查将始终返回相同的结果(true false,在这种情况下,它应该是 false,因为 Product 还应该覆盖这些函数并检查 other 也是一个 产品并检查每个相关属性等)。

请参阅 Joshua Bloch 的 Effective Java,第二版 中的“第 8 条:重写 equals 时遵守一般契约”和“第 9 条:重写 equals 时始终重写 hashCode”,了解有关这些内容的更多详细信息契约以及围绕分层值(value)类别的不同方法的问题。

关于java - hashCode() 应该返回对象的唯一 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43401993/

相关文章:

java - Thales HSM - Windows cp 1252 成功/Linux UTF-8 失败

java - Android Fragment 导致 NullPointerException

Java:为第三方类实现hashCode和equals可以吗?

java - 为非常简单的类实现 `hashCode()`

android - Exoplayer2 流式传输 HLS 视频,有时仅播放有声视频(视频未播放)

Java 树形图 : Different object after "put"?

java - Java 新手 - 什么是 JPA 和 DAO?

java - 在 JAVAEE Glassfish 中启用 FormDataMultiPart 或 @FormDataParam

java - 使用Gradle和IntellIJ时Kotlin中未解析的引用 “java”

用于 fragment 中状态流的 Android 通用函数