如果hashCode()返回一个对象的唯一ID

在我的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)方法equals(Object) ,那么在两个对象的每一个上调用hashCode方法必须产生相同的整数结果。
  • 不要求如果两个对象根据equals(Object)方法是不相等的,那么对这两个对象的每一个调用hashCode方法必须产生不同的整数结果。 但是,程序员应该知道,为不相等的对象生成不同的整数结果可以提高散列表的性能。

我的问题是:

hashCode()返回这个唯一标识符是否是一个好习惯?

注:我知道在Kotlin中,我们可以使用data类,以便编译器自动派生预定义的成员,如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() 

在基类中实现这些函数,而不是在具体的子类中重写它们可能会导致equalshashCode合同上的违规。

如果你不强制子类实现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并检查每个相关财产等)。

在Joshua Bloch的Effective Java,Second Edition中 ,请参阅“第8项:在重写equals时服从一般合同”和第9项:总是覆盖hashCode 以获取有关这些合同的更多细节以及围绕不同分层值类。