在我的 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 thehashCode
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 thehashCode
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
用于数据类(也称为值类),因此应将equals
和hashCode
定义为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/