set 不包含等于其成员之一的项目?

Posted

技术标签:

【中文标题】set 不包含等于其成员之一的项目?【英文标题】:set does not contain an item that equals one of its members? 【发布时间】:2019-05-20 09:38:54 【问题描述】:

所以根据the Java API,Set::contains

当且仅当此集合包含一个元素 e 满足 (o==null ? e==null : o.equals(e)) 时才返回 true

那么...为什么即使集合中恰好包含一个等于creds 的元素,此方法也会返回false?

private boolean validate(Credentials creds)
    Set<Credentials> acceptedUsers = getAcceptedUsers();
    return acceptedUsers.contains(creds);

更具体地说,我插入了一些printlns

private boolean validate(Credentials creds)
    Set<Credentials> acceptedUsers = getAcceptedUsers();

    System.out.print("accepted users: ");
    System.out.println(acceptedUsers);
    System.out.print("accessing user: ");
    System.out.println(creds);
    System.out.println("items are equal: " + acceptedUsers.stream().map(c -> c.equals(creds)).collect(Collectors.toSet()));
    System.out.println("access ok: " + (acceptedUsers.contains(creds) ? "YES" : "NO"));

    return acceptedUsers.contains(creds);

这就是它不得不说的:

accepted users: [[
    foo
    FCDE2B2EDBA56BF408601FB721FE9B5C338D10EE429EA04FAE5511B68FBF8FB9
]]
accessing user: [
    foo
    FCDE2B2EDBA56BF408601FB721FE9B5C338D10EE429EA04FAE5511B68FBF8FB9
]
items are equal: [true]
access ok: NO

getAcceptedUsers 当前返回一个虚拟集

private Set<Credentials> getAcceptedUsers()
    return new HashSet<Credentials>()add(new Credentials("foo","bar", false));;

Credentials 被实现为

class Credentials
    final String username;
    final String password;

    public Credentials(String username, String password, boolean isPasswordHashed) 
        this.username = username;

        if(isPasswordHashed) this.password = password;
        else 
            MessageDigest md;
            try 
                md = MessageDigest.getInstance("SHA-256");
             catch (NoSuchAlgorithmException e) 
                throw new IllegalStateException(e);
            

            md.update(password.getBytes());
            byte[] hash = md.digest();

            this.password = (new HexBinaryAdapter()).marshal(hash);
        
    

    @Override
    public boolean equals(Object obj) 
        if(obj == null) return false;
        if(!(obj instanceof Credentials)) return false;
        Credentials other = (Credentials)obj;
        return this.username.equals(other.username) && this.password.equals(other.password);
    

    @Override
    public String toString() 
        return String.format("[\n\t%s\n\t%s\n]", username,password);
    

【问题讨论】:

【参考方案1】:

实现equals方法是不够的,你还必须实现hashCode

就像你可以阅读here:

返回此集合的哈希码值。集合的哈希码定义为集合中元素的哈希码之和,其中空元素的哈希码定义为零。这确保了 s1.equals(s2) 意味着任何两个集合 s1 和 s2 的 s1.hashCode()==s2.hashCode(),这是 Object.hashCode() 的一般合同所要求的。

【讨论】:

我知道你可以在 *** 上做什么。 XD 但是有一个时间限制,您还不能接受答案。 我的一个同事刚遇到同样的问题,和你说了同样的话^^我想我们都忘记了一次,然后一劳永逸地学习。【参考方案2】:

如果您想使用HashMapHashSet,您需要重写hashCode() 方法,以便相等的对象具有相同的哈希码。例如:

@Override
public int hashCode() 
    return Objects.hash(username, password);

【讨论】:

以上是关于set 不包含等于其成员之一的项目?的主要内容,如果未能解决你的问题,请参考以下文章

IEnumerable 中的项目不等于 List 中的项目

为啥结构的大小不等于其各个成员类型的大小之和? [复制]

当我在 settings.gradle 文件中包含项目时,如何不包含构建任务?

ListView 不刷新其项目

Set以及数组去重

Visual Studio 项目:缺少 Properties/Settings.settings