我应该如何实施hashCode()和equals()在Java下面的类?
class Emp
{
int empid ; // unique across all the departments
String name;
String dept_name ;
String code ; // unique for the department
}
Run Code Online (Sandbox Code Playgroud) 我发现自己想要覆盖一个对象的哈希码和==,我想知道是否有关于如何实现依赖于多个属性的哈希码的最佳实践,并且似乎有一些特定于Dart的注意事项.
最简单的答案是将所有属性的哈希值混合在一起,这可能不是太糟糕.在Dart Up和Running中也有一个例子,网址是https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html
// Override hashCode using strategy from Effective Java, Chapter 11.
int get hashCode {
int result = 17;
result = 37 * result + firstName.hashCode;
result = 37 * result + lastName.hashCode;
return result;
}
Run Code Online (Sandbox Code Playgroud)
但似乎它期望截断整数语义,并且在Dart中溢出JS整数的范围似乎不适合散列.
我们也可以这样做,并在每次操作后截断为32位.
对于我的应用程序,预期的集合大小非常小,几乎任何事情都可以,但我很惊讶没有看到一般情况的标准配方.有没有人有这方面的经验或经验?
我有一些Java代码,我正在翻译成Scala.
代码由一些不可变的类组成,这些类符合case classScala中的目的.
但我不想引入错误,因此我想确保为当前实现生成的代码equals和hashCode/ 和/的行为等效.
我已经看过"Scala编程",但它只是说
第三,编译器将方法的"自然"实现添加到String,hashCode,并且等于你的类.
当我点击这段时,我正在阅读Eric Lippert 关于GetHashCode指南和规则的最新博客帖子:
我们在这里可能更聪明; 就像List在它满了时调整自身大小一样,bucket set也可以自行调整大小,以确保平均bucket长度保持低位.此外,由于技术原因,通常最好将存储桶设置长度设为素数,而不是100.我们可以对此哈希表进行大量改进.但是这个哈希表的简单实现的快速草图现在可以做到.我想保持简单.
所以看起来我错过了一些东西.为什么将它设置为素数是一个好习惯?
我只是想知道覆盖equals和hashCode可变集合是否是一个好主意.这意味着如果我将这样的集合插入a HashSet然后修改集合,HashSet则将无法再找到该集合.这是否意味着,只有永恒不变的藏品应该重写equals和hashCode,或者是这种滋扰Java程序员简单地生活?
在Python中,我知道__hash__给定对象的值返回应该与该对象的生命周期相同.但是,出于好奇,如果不是,会发生什么?这会造成什么样的破坏?
class BadIdea(object):
def __hash__(self):
return random.randint(0, 10000)
Run Code Online (Sandbox Code Playgroud)
我知道__contains__并且__getitem__会表现得很奇怪,因此,dicts和sets会表现得很奇怪.你也可能在dict/set中得到"孤立"值.
还有什么可能发生的?它可能会使解释器崩溃,还是破坏内部结构?
当覆盖java.lang.Object的equals()函数时,javadocs建议,
通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相等的哈希代码.
hashCode()方法必须为每个对象返回一个唯一的整数(这在基于内存位置比较对象时很容易,只需返回对象的唯一整数地址)
应该如何覆盖hashCode()方法,以便它仅基于该对象的特性为每个对象返回一个唯一的整数?
public class People{
public String name;
public int age;
public int hashCode(){
// How to get a unique integer based on name and age?
}
}
/*******************************/
public class App{
public static void main( String args[] ){
People mike = new People();
People melissa = new People();
mike.name = "mike";
mike.age = 23;
melissa.name = "melissa";
melissa.age = 24;
System.out.println( mike.hasCode() ); // output?
System.out.println( melissa.hashCode(); // output?
}
}
Run Code Online (Sandbox Code Playgroud) 如果我理解正确,在.NET中,默认实现Object.GetHashCode()返回一个基于对象的内存地址的值(至少对于引用类型).但是,垃圾收集器可以在内存中自由移动对象.据推测,哈希代码不会因为GC移动对象而改变,所以这种交互是否有特殊处理,或者我的假设是错误的?
什么是基本类型的哈希码,例如int?
例如,让我们说num是一个整数.
int hasCode = 0;
if (num != 0) {
hasCode = hasCode + num.hashCode();
}
Run Code Online (Sandbox Code Playgroud) 在Javadoc for Object.hashCode()中声明
尽管合理实用,但是由class定义的hashCode方法
Object确实为不同的对象返回了不同的整数.(这通常通过将对象的内部地址转换为整数来实现,但Java™编程语言不需要此实现技术.)
这是一个常见的miconception,这与内存地址有关,但它并没有因为它可以在没有通知的情况下改变,而hashCode()不会,也不能改变对象.
@Neet提供了一个很好的答案的链接/sf/answers/39579151/但我正在寻找更多细节.
这是一个例子来说明我的担忧
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
for (int t = 0; t < 10; t++) {
System.gc();
Object[] objects = new Object[10];
for (int i = 0; i < objects.length; i++)
objects[i] = new Object();
for (int i = 0; i < objects.length; i++) {
if (i > 0) System.out.print(", ");
int location = unsafe.getInt(objects, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * i);
System.out.printf("%08x: hc= …Run Code Online (Sandbox Code Playgroud)