Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用带有自定义键的HashMap_Java_Map - Fatal编程技术网

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