当前位置: 首页 > 知识库问答 >
问题:

Java-HashMap和HashSet不受object.hashCode()的支持?

张翰海
2023-03-14

我正在尝试编写一个服务器,它通过使用hashmap 唯一生成的ID来跟踪其客户端。这个想法是,如果我是管理员,并且我想从服务器上引导某人,我就为该客户机查找适当的ClientID(它实际上只是一个字符串;唯一的区别是ClientID类负责确保没有两个客户机被分配了相同的ID),然后输入一个命令,如“kick 12”(如果我想要kick的人的ClientID碰巧是12)。我认为这是可行的,因为我认为hashmap可能是通过内部使用从Object继承的hashCode()方法来支持的,并且我设计了ClientID类,以支持必要的查找操作,假设这是真的。但显然,这不是真的--在HashMap(或HashSet)中,具有相同哈希代码的两个键显然不被认为是相同的键。我使用hashset创建了一个简单的示例来说明我想要做什么:

import java.lang.*;
import java.io.*;
import java.util.*;

class ClientID {
    private String id;

    public ClientID(String myId)
    {
        id = myId;
    }

    public static ClientID generateNew(Set<ClientID> existing)
    {
        ClientID res = new ClientID("");
        Random rand = new Random();
        do {
            int p = rand.nextInt(10);
            res.id += p;
        } while (existing.contains(res));
        return res;
    }

    public int hashCode()
    {
        return (id.hashCode());
    }

    public boolean equals(String otherID)
    {
        return (id == otherID);
    }

    public boolean equals(ClientID other)
    {
        return (id == other.id);
    }

    public String toString()
    {
        return id;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        HashSet<ClientID> mySet = new HashSet<ClientID>();
        ClientID myId = ClientID.generateNew(mySet);
        mySet.add(myId);
        String input;
        do {
            System.out.println("List of IDs/hashcodes in the set: ");
            for (ClientID x: mySet)
                System.out.println("\t" + x.toString() + "\t" + x.hashCode());
            System.out.print("\nEnter an ID to test if it's in the set: ");
            input = in.readLine();
            if (input == null)
                break;
            else if (input.length() == 0)
                continue;
            ClientID matchID = new ClientID(input);
            if (mySet.contains(matchID))
                System.out.println("Success! Set already contains that ID :)");
            else {
                System.out.println("Adding ID " + matchID.toString() + " (hashcode " + matchID.hashCode() + ") to the set");
                mySet.add(matchID);
            }
            System.out.println("\n");
        } while (!input.toUpperCase().equals("QUIT"));
    }
}

使用此代码,不可能(据我所知)生成输出

Success! Set already contains that ID :)

...相反,它将继续向该集合添加值,即使这些值是重复的(也就是说,它们与equals方法相等,并且具有相同的hashcode)。如果我不能很好地与你交流,你可以自己运行代码,我想你很快就会明白我的意思...这使得查找变得不可能(这也意味着client.generateNew方法根本无法按照我的预期工作);我该怎么绕过这件事?

共有2个答案

拓拔曦
2023-03-14

hashset(和hashmap)使用object.hashcode方法确定对象应进入哪个哈希桶,但不确定该对象是否等于该桶中的另一个对象。为此,他们使用object.equals。在您的示例中,尝试使用字符串ID的引用相等来实现该方法--不是“实际”相等,而是字符串相等。您还创建了equals的新重载,而不是重写object.equals

您可以在SO上搜索许多关于为什么不能使用==比较字符串的问题,但TL;DR版本需要重写布尔等于(Object)(不是重载的同名方法,而是该方法--它必须接受Object),并检查传入对象是否是一个ClientID,其字符串id等于(ont==)这个ClientID的字符串id。

杜良骏
2023-03-14

在Java中,一个特定的类要在哈希中充当键,它必须实现两个方法。

public int hashCode();
public boolean equals(Object o);

这些方法必须连贯地操作:如果一个对象等于另一个对象,那些对象必须产生相同的哈希。

注意的签名等于(Object o)。您的equals方法正在重载equals,但您必须重写equals(Object)

正如其他人所指出的,重写的equals方法也被破坏,因为您比较的是string标识,而不是值。不是通过str1==str2进行比较,而是使用str1.equals(str2)

对您的代码做以下修改,事情就应该开始正常工作了。

public boolean equals(Object o){
    return o instanceof ClientID ? this.equals((ClientID) o);
}

public boolean equals(String otherID) {
    return id.equals(otherID);
}

public boolean equals(ClientID other) {
    return id.equals(other.id);
}
 类似资料:
  • 问题内容: 我了解这是基于实现的,但是在您需要唯一的元素集时使用。那么,为什么在下一个代码中将相同的对象放入地图并进行设置时,两个集合的大小都等于1?地图大小不应该为2吗?因为如果两个集合的大小相等,那么使用这两个集合不会有任何区别。 输出为1和1。 问题答案: 该地图拥有唯一键。当您使用映射中存在的键进行调用时,该键下的对象将被新对象替换。因此大小为1。 两者之间的区别应该很明显: 在您存储键值

  • 如果Equals方法返回false,即返回false。所以这些值应该相加两次,但只相加一次。谁能解释一下。我在谷歌上搜索并清除了关于HashCode和equals contract的概念,但在这里我失败了。

  • 本文向大家介绍HashMap 和 HashSet的区别,包括了HashMap 和 HashSet的区别的使用技巧和注意事项,需要的朋友参考一下 HashMap和HashSet的区别是Java面试中最常被问到的问题。如果没有涉及到Collection框架以及多线程的面试,可以说是不完整。而Collection框架的问题不涉及到HashSet和HashMap,也可以说是不完整。HashMap和Hash

  • 本文向大家介绍HashMap 和 HashSet区别?相关面试题,主要包含被问及HashMap 和 HashSet区别?时的应答技巧和注意事项,需要的朋友参考一下 如果你看过 `HashSet` 源码的话就应该知道: HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 `clone() `、`writeObject()`、`readObject()`

  • 本文向大家介绍Java中的HashMap和HashSet之间的区别。,包括了Java中的HashMap和HashSet之间的区别。的使用技巧和注意事项,需要的朋友参考一下 HashMap和HashSet都是Java Collection框架最重要的类之一。 以下是HashMap和HashSet之间的重要区别。 序号 键 哈希映射 哈希集 1 实作 Hashmap是Map接口的实现。 另一方面,哈希

  • 问题内容: 除了不允许重复值的事实之外,和之间有什么区别? 我的意思是实施明智?这有点含糊,因为它们都使用 哈希表 存储值。 问题答案: 它们是完全不同的构造。A 是的实现。一个地图键映射到值。密钥查找使用哈希进行。 另一方面,a 是的实现。一组被设计成一组的数学模型相匹配。一个不使用支持其实现,正如你指出。但是,它实现了完全不同的接口。 当您寻找最适合您的目的时,本教程是一个很好的起点。如果您真