快速的问题:如果我想使用HashMap
使用自定义类为关键,我必须重写hashCode
功能? 它将如何,如果我不重写功能工作?
Answer 1:
从技术上讲,你不必,只要相等的对象有相同的hashCode覆盖hashCode方法。
所以,如果你使用的对象,其中定义等于默认行为只能针对相同的实例返回true,那么你就必须重写hashCode方法。
但是,如果你没有重载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
在实践中,你经常有关键的只有一个实例,所以在技术上你没有重载equals和hashCode方法。
但它的覆盖反正用作键的类的equals和hashCode方法的最佳做法,因为稍后您或其他开发人员可能会忘记,同一实例必须使用,这可能会导致难以跟踪的问题。
并注意:即使你重写equals和hashCode方法,你必须确保你不改变的方式,将改变了equals或hashCode方法的结果的关键对象,否则地图将无法找到自己的价值了。 这就是为什么我们建议尽可能使用不可变对象作为键。
Answer 2:
如果不重写了hashCode和equals你会得到默认行为是每个对象是不同的,无论其内容。
Answer 3:
唯一的一次,你不必重写hashCode()
函数是当你还没有覆盖equals
,让你使用默认Object.equals
参考平等的定义。 这可能是也可能不是你想要的-特别是,不同的对象将不会被认为是相等的,即使他们有相同的字段值。
如果重写equals
但不hashCode
, HashMap
行为将是不确定的(阅读:它不会使任何意义,并会完全损坏)。
Answer 4:
这取决于你所使用作为重点对象类。 如果它是一个自定义类,像你这样的建议,并没有延伸任何东西(即它扩展Object
),那么哈希码功能将是的Object
,并会考虑内存的引用,使得看起来你返回相同的两个对象不同的代码。
所以,是的,除非你是扩展一个类具有hashCode()
函数,你知道你的作品,你需要实现自己的。 另外,还要确保实现equals()
:有的类,如ArrayList
只使用相当于而其他类似的HashMap将检查两个hashCode()
和equals()
。
Answer 5:
想想也是,如果你的关键并不是一成不变的,你可能有问题。 如果你把一个可变键的条目在地图上的更改后的方式,它会影响哈希码,等于你可能会失去在地图上您的项目,你将无法再检索它的关键。
Answer 6:
你应该重写equals()
和hashCode()
从Object类的方法。 在默认的实现equals()
和hashcode()
,这是从继承java.lang.Object
使用一个对象实例的存储位置(例如MyObject@6c60f2ea
)。 这可能会导致问题,当一个对象的两个实例具有相同的属性,但继承的equals()
将返回false
,因为它使用的memory location
,这是两个不同的实例。
还有toString()
方法可以被重写以提供您的对象的适当的字符串表示。
实现用户定义的键时的主要考虑因素
- 如果一个类重写
equals()
它必须覆盖hashCode()
。 - 如果2个对象是相等的,那么它们
hashCode
值必须相等。 - 如果某个字段是不是在使用
equals()
,那么就不能在使用hashCode()
- 如果是经常访问
hashCode()
是用于缓存以提高性能的候选人。