Java 使用带有自定义键的HashMap
快速问题:如果我想使用自定义类作为键的Java 使用带有自定义键的HashMap,java,map,Java,Map,快速问题:如果我想使用自定义类作为键的HashMap,必须重写hashCode函数吗?如果我不重写该函数,它将如何工作?您唯一不必重写hashCode()函数的时间是您也不重写equals,因此您使用默认的对象.equals引用相等的定义。这可能是您想要的,也可能不是您想要的——特别是,不同的对象即使具有相同的字段值,也不会被认为是相等的 如果覆盖equals但不覆盖hashCode,HashMap行为将是未定义的(读:它毫无意义,并且将完全损坏)。如果不覆盖hashCode和equals,则将
HashMap
,必须重写hashCode
函数吗?如果我不重写该函数,它将如何工作?您唯一不必重写hashCode()
函数的时间是您也不重写equals
,因此您使用默认的对象.equals
引用相等的定义。这可能是您想要的,也可能不是您想要的——特别是,不同的对象即使具有相同的字段值,也不会被认为是相等的
如果覆盖
equals
但不覆盖hashCode
,HashMap
行为将是未定义的(读:它毫无意义,并且将完全损坏)。如果不覆盖hashCode和equals,则将获得默认行为,即每个对象都不同,无论其内容如何。它取决于用作键的对象类。如果它是你建议的自定义类,并且它不扩展任何东西(即它扩展<代码>对象< /代码>),那么HASCODE函数将是<代码>对象< /代码>,并且将考虑内存引用,使两个看起来与你相同的对象散列到不同的代码。
因此,是的,除非您使用已知适合您的
hashCode()
函数扩展一个类,否则您需要实现自己的类。还要确保实现equals()
:一些类,如ArrayList
,将只使用equals,而其他类,如HashMap,将同时检查hashCode()
和equals()
还要考虑,如果密钥不是不可变的,则可能会出现问题。如果您在映射中放置一个带有可变键的条目,您稍后会以影响hashcode和equals的方式更改该键,您可能会丢失映射中的条目,因为您将无法再检索它。从技术上讲,只要相同的对象具有相同的hashcode,您就不必重写hashcode方法
因此,如果您使用由Object定义的默认行为,其中equals仅对同一实例返回true,那么您不必重写hashCode方法
但如果不重写equals和hashCode方法,则意味着您必须确保始终使用相同的键实例
例如:
实际上,您通常只有一个键实例,因此从技术上讲,您不必重写equals和hashCode方法
但最好的做法是重写用作键的类的equals和hashCode方法,因为稍后您或其他开发人员可能会忘记必须使用相同的实例,这可能会导致难以跟踪的问题
注意:即使覆盖equals和hashCode方法,也必须确保更改key对象的方式不会改变equals或hashCode方法的结果,否则映射将无法再找到您的值。这就是为什么建议尽可能使用不可变对象作为键。您应该重写Object类中的
equals()
和hashCode()
方法。继承自java.lang.Object
的equals()
和hashcode()
的默认实现使用对象实例的内存位置(例如MyObject@6c60f2ea
)。当一个对象的两个实例具有相同的属性时,这可能会导致问题,但继承的equals()
将返回false
,因为它使用内存位置,这对于两个实例是不同的
还可以重写toString()
方法,以提供对象的正确字符串表示形式
实现用户定义密钥时的主要注意事项
如果类重写了equals()
,它必须重写hashCode()
如果两个对象相等,则它们的hashCode
值也必须相等
如果字段未在equals()
中使用,则不得在hashCode()
中使用
如果经常访问它,hashCode()
是缓存以提高性能的候选者
除非他在扩展一个对他有用的哈希代码,否则你是绝对正确的。只是检查了HashMap.put()以确定,我确实弄错了。谢谢我修正了答案以反映您的评论。如果不检查实现细节,您可以看到,在抽象级别上,由于哈希冲突的不可撤销性,答案一定是这样。如果不考虑equals
,任何两个对象在hashcode上发生碰撞,结果都是一样的。
MyKey key1_1 = new MyKey("key1");
myMap.put(key1_1,someValue); // OK
someValue = myMap.get(key1_1); // returns the correct value, since the same key instance has been used;
MyKey key1_2 = new MaKey("key1"); // different key instance
someValue = myMap.get(key1_2); // returns null, because key1_2 has a different hashCode than key1_1 and key1_1.equals(key1_2) == false