Java HashMap包含奇怪的行为

时间:2015-12-03 13:39:39

标签: java hashmap equals

试图将简单的任务陷入奇怪的问题:

class User{
    String login;
    String pwrd;
    User(String lg,String pw){
        this.login=lg;
        this.pwrd=pw;
    }
    public String toString(){
        return this.login;
    }
    public boolean equals(String a){
        return this.login.equals(a);
    }
    public boolean equals(User t){
        return this.login.equals(t.toString());
    }
}

public class Foo{
    public static void main (String[] args)
    {
        HashMap<User,Boolean> a=new HashMap<>();
        User a1=new User("asd","123"),a2=new User("asd","134");
        a.put(a1,false);
        a.put(a2,false);
        System.out.println(a.containsKey(a2));
        System.out.println(a.containsKey("asd"));
    }
}

结果我希望两个containsKey检查都是真的。进一步在代码中它将被越来越多地使用。所以首先要理解为什么它表现如此,如果可能的话修复它。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:7)

地图的键是User个实例,因此a.containsKey("asd")永远不会返回true,因为“asd”是一个字符串。

顺便说一下,你没有覆盖Object的{​​{1}},它需要一个equals参数。这意味着Object也会返回a.containsKey(a2),因为false为false。

a1==a2的正确实施将是:

equals

正如Andy所说,你还必须覆盖@Override public boolean equals(Object other){ if (!(other instanceof User)) return false; User u = (User) other; return this.login.equals(u.login); } ,这样如果hashCode为真,那么a.equals(b)

编辑:

我认为,如果您以a.hashCode()==b.hashCode()实例与a.containsKey("asd")实例相等的方式覆盖equals String,如果它们与{User匹配,则可以使login返回true 1}} property:

@Override
public boolean equals(Object other){
    if (other instanceof User) {
        User u = (User) other;
        return this.login.equals(u.login);
    } else if (other instanceof String) {
        String u = (String) other;
        return this.login.equals(u);
    }
    return false;
}

@Override
public int hashCode()
{
    return login.hashCode();
}

我从未尝试过equals这样的实现,但根据我对HashMap的理解,它可能有用。

但是,equals的此类实施会违反equals的Javadoc中定义的Object合同,因为即使"asd".equals(a1) a1.equals("asd")将返回false是真的。

编辑:

在检查HashMap的实现后,我发现equals的这种实现不起作用,因为containsKey(key)的代码将密钥与现有条目的密钥进行比较而不是反过来说,如果String.equals(obj)不是objString将始终返回false。我想有一个很好的理由不打破equals的合同。

答案 1 :(得分:1)

您需要覆盖public boolean equals(Object other)并在该方法内部检查传递的其他对象的正确类型。请注意,传递的对象也可能为null

public class User {
  public boolean equals(Object other) {
    //Is the same
    if(other == this) {
      return true;
    }
    //Other is a user as well - Includes null-check (thanks, Kevin!)
    if(other instanceof User) {
      //equal if usernames are equal
      return login.equals(other.login);
    }
    //anything else - not equal / null, whatever
    return false;
  }
}