2014-12-20 67 views
1

我已经创建了一个名为Coordinates的类,它只保留一些xy整数。我想用这个作为HashMap的关键。创建可用作散列映射关键字的Java类

不过,我注意到,当你创建的Coordinates两个不同的实例具有相同xy值,它们被用作通过散列图不同的密钥。也就是说,即使它们都具有相同的坐标,也可以放入两个条目。

我已经重写equals()

public boolean equals(Object obj) { 
    if (!(obj instanceof Coord)) { 
     return false; 
    }else if (obj == this) { 
     return true; 
    } 
    Coord other = (Coord)obj; 
    return (x == other.x && y == other.y); 
} 

HashMap仍然采用了两个实例,好像他们是不同的密钥。我该怎么办?

而且我知道我可以用两个元素的整数数组来代替。但我想用这个班。

+7

你重写了'hashcode'吗? –

+0

@邹邹哦,不,我不知道。我看到它返回一个整数。我应该返回什么?当然,这不是x和y的总和。 – Voldemort

+1

你需要保持一致。如果a等于b,则a.hashcode == b.hashcode。另请参见http://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java –

回答

6

你需要重写hashCode。 Java 7为此提供了一种实用方法。

@Override 
public int hashCode() { 
    return Objects.hash(x, y); 
} 
+1

为什么它需要将是很好的说明,但指出了该实用程序类感谢,我不知道它,它提供了一些有用的方法:) – Dici

+0

从http://tutorials.jenkov.com/java-collections/hashcode-equals.html *当插入对象使用一个密钥hastable。计算此密钥的哈希码,并用于确定内部存储对象的位置。当你需要在散列表中查找一个对象时,你也可以使用一个键。计算该密钥的哈希码并用于确定在哪里搜索该对象。* – wassgren

4

你也应该重写hashCode(),这样两个相等的情况下,具有相同的hashCode()。例如: -

@Override 
public int hashCode() { 
    int result = x; 
    result = 31 * result + y; 
    return result; 
} 

注意,它不是严格要求的两个实例中不等于有不同的散列码,但你有少的碰撞,更好的性能,你会得到从你们HashMap

1

哈希映射使用对象的hashCode方法来确定将对象放入哪个存储桶。 如果您的对象不执行hashCode,它将继承Object的默认实现。从docs

尽管合理实用,类Object定义的hashCode方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但JavaTM编程语言不需要此实现技术。)

因此,每个对象看起来都是不同的。

需要注意的是不同的对象可能会返回相同hashCode。这就是所谓的冲突。 当发生这种情况时, 然后除了hashCode, 哈希映射实现将使用equals方法来确定两个对象是否相等。

请注意,大多数IDE提供从您的类中定义的字段生成equalshashCode方法。实际上,IntelliJ鼓励同时定义这两种方法。有充分的理由。这两种方法有密切的关系, ,只要你改变了其中的一个,或实现其中之一,或重写其中之一, 必须查看(并极有可能改变),另一只也。

这个类中的方法是100%,生成的代码(通过的IntelliJ):

class Coord { 
    private int x; 
    private int y; 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     Coord coord = (Coord) o; 

     if (x != coord.x) return false; 
     if (y != coord.y) return false; 

     return true; 
    } 

    @Override 
    public int hashCode() { 
     int result = x; 
     result = 31 * result + y; 
     return result; 
    } 
} 
0

你可能没有覆盖hashCode方法。为什么要求?要回答这个问题,你必须了解哈希表的工作原理。

的散列表是基本上linkedlists的阵列。阵列中的每个桶对应于特定值hashCode % numberOfBuckets。都具有相同的hashCode % numberOfBuckets对象将被存储在链表内的相关联的桶和将认识基础上他们的equals方法(查找例如期间)。因此,确切的规格是a.hashCode() != b.hashCode() => !a.equals(b),相当于a.equals(b) => a.hashCode() == b.hashCode()

如果您使用基于引用的默认实现hashCode,那么两个相等但具有不同引用(因此,最可能是不同的hashCode)的对象将存储在不同的存储桶中,导致重复的密钥。