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

时间:2017-04-13 21:27:18

标签: 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规范:

之后
  
      
  • 每当在执行应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的等比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。
  •   
  • 如果两个对象根据equals(Object)方法相等,则在两个对象中的每一个上调用hashCode方法必须生成相同的整数结果。
  •   
  • 如果两个对象根据equals(Object)方法不相等则不是必需的,那么在两个对象中的每一个上调用hashCode方法必须产生不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
  •   

我的问题是:

hashCode()中返回此唯一标识符是一种好习惯吗?

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

1 个答案:

答案 0 :(得分:2)

由于您的抽象BaseClass用于数据类(也就是值类),它应该将equalshashCode定义为abstract并强制实现具体类来实现它们。 e.g:

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合同。

如果您不强制子类实施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根据他们的合同实施,那么两个等式检查将始终返回相同的结果(truefalse,在这种情况下它应该是false Product也应该覆盖这些功能并检查other是否也是Product并检查每个相关的属性等。)

参见&#34;第8项:在覆盖等于&#34;时遵守总合同。和&#34;项目9:当你重写equals&#34;时总是覆盖hashCode Joshua Bloch撰写的 Effective Java,Second Edition 中有关这些合同的更多详细信息以及有关层次价值类别的不同方法的问题。