我似乎在标准的Java HashMap中得到了重复的键。所谓“复制”,我的意思是键通过它们的equals()
方法是相等的。下面是有问题的代码:
import java.util.Map;
import java.util.HashMap;
public class User {
private String userId;
public User(String userId) {
this.userId = userId;
}
public boolean equals(User other) {
return userId.equals(other.getUserId());
}
public int hashCode() {
return userId.hashCode();
}
public String toString() {
return userId;
}
public static void main(String[] args) {
User arvo1 = new User("Arvo-Part");
User arvo2 = new User("Arvo-Part");
Map<User,Integer> map = new HashMap<User,Integer>();
map.put(arvo1,1);
map.put(arvo2,2);
System.out.println("arvo1.equals(arvo2): " + arvo1.equals(arvo2));
System.out.println("map: " + map.toString());
System.out.println("arvo1 hash: " + arvo1.hashCode());
System.out.println("arvo2 hash: " + arvo2.hashCode());
System.out.println("map.get(arvo1): " + map.get(arvo1));
System.out.println("map.get(arvo2): " + map.get(arvo2));
System.out.println("map.get(arvo2): " + map.get(arvo2));
System.out.println("map.get(arvo1): " + map.get(arvo1));
}
}
下面是结果输出:
arvo1.equals(arvo2): true
map: {Arvo-Part=1, Arvo-Part=2}
arvo1 hash: 164585782
arvo2 hash: 164585782
map.get(arvo1): 1
map.get(arvo2): 2
map.get(arvo2): 2
map.get(arvo1): 1
如您所见,两个User
对象上的equals()
方法返回true
,它们的散列代码相同,但它们各自在map
中形成一个不同的key
。此外,map
在最后四个User
调用中继续区分两个get()
密钥。
这直接与documentation相矛盾
更正式地说,如果此映射包含从键k到值v的映射,则(key==null?k==null : key.equals(k)),则此方法返回v;否则返回null。(最多只能有一个这样的映射。)
这是一个bug吗?我是不是漏掉了什么?我运行的是Java版本的1.8.0_92,它是我通过Homebrew安装的。
编辑:此问题已被标记为此other question的副本,但我将保留此问题不变,因为它确定了与equals()
似乎不一致,而另一个问题假定错误出在hashCode()
上。希望这个问题的存在将使这个问题更容易搜索。
发布于 2016-07-15 14:08:23
问题出在您的equals()
方法中。Object.equals()
的签名是equals(OBJECT)
,但在本例中它是equals(USER)
,所以这是两个完全不同的方法,并且散列映射调用的是带有Object
参数的方法。您可以通过将@Override
注释放在您的equals上来验证这一点-它将生成一个编译器错误。
equals方法应该是:
@Override
public boolean equals(Object other) {
if(other instanceof User){
User user = (User) other;
return userId.equals(user.userId);
}
return false;
}
作为最佳实践,您应该始终将@Override
放在您所覆盖的方法上-它可以为您省去很多麻烦。
发布于 2016-07-15 14:08:12
您的equals方法不会重写equals
,而且Map
中的类型会在运行时被擦除,因此实际调用的equals方法是equals(Object)
。你的等号应该看起来更像这样:
@Override
public boolean equals(Object other) {
if (!(other instanceof User))
return false;
User u = (User)other;
return userId.equals(u.userId);
}
发布于 2016-07-15 14:12:49
好的,首先,代码不能编译。缺少此方法:
other.getUserId()
但是除此之外,你还需要@Override equals
方法,像Eclipse这样的集成开发环境也可以帮助生成equals
和hashCode
btw。
@Override
public boolean equals(Object obj)
{
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
User other = (User) obj;
if(userId == null)
{
if(other.userId != null)
return false;
}
else if(!userId.equals(other.userId))
return false;
return true;
}
https://stackoverflow.com/questions/38388751
复制相似问题