试图实现简单的任务陷入奇怪的问题:
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) { HashMapa=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
检查都是真的.进一步在代码中它将被越来越多地使用.所以首先要理解为什么它表现如此,如果可能的话修复它.任何帮助赞赏.
Map的键是User
实例,所以a.containsKey("asd")
永远不会返回true
,因为"asd"是一个String.
顺便说一下,你没有覆盖Object
's equals
,它需要一个Object
参数.这意味着a.containsKey(a2)
也返回false
,因为a1==a2
是假的.
正确的实施equals
将是:
@Override public boolean equals(Object other){ if (!(other instanceof User)) return false; User u = (User) other; return this.login.equals(u.login); }
正如Andy所提到的,你也必须覆盖hashCode
,所以如果a.equals(b)
是真的那么a.hashCode()==b.hashCode()
.
编辑:
我认为a.containsKey("asd")
如果你equals
以一种将String
实例视为与你的User
实例相等的方式覆盖(如果它们与login
属性匹配),则可以返回true :
@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)
如果obj
不是a ,则总是返回false String
.我想有一个很好的理由不打破合同equals
.