1

我有一个非常简单的 Pair 类,定义如下:

public class Pair<L, R> {

    private L left;
    private R right;

    public Pair(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public L getLeft() {
        return this.left;
    }

    public R getRight() {
        return this.right;
    }

    public String toString() {
        return String.format("(%s, %s)", left, right);
    }

    public int hashCode() {
        int hashFirst = left != null ? left.hashCode() : 0;
        int hashSecond = left != null ? right.hashCode() : 0;

        return (hashFirst + hashSecond) * hashSecond + hashFirst;
    }

    public Boolean equals(Pair other) {
        if (other == null) {
            return false;
        }

        return left.equals(other.getLeft()) && right.equals(other.getRight());
    }
}

然后我有一个 Position 类定义如下:

public class Position {

    private Pair<Integer, Integer> pair;

    public Position(Integer x, Integer y) {
        this.pair = new Pair<Integer, Integer>(x, y);
    }

    public Integer getX() {
        return this.pair.getLeft();
    }

    public Integer getY() {
        return this.pair.getRight();
    }

    public boolean equals(Position other) {
        if (other == null) {
            return false;
        }

        boolean b = getX() == other.getX() && getY() == other.getY();
        System.out.println(String.format("%s.equals(%s): %s", this, other, b));
        return b;
    }

    public int hashCode() {
        return pair.hashCode();
    }

    public String toString() {
        return String.format("(%d, %d)", this.pair.getLeft(),
                              this.pair.getRight());
    }

}

这一切都很好。但是,当我尝试对其进行测试时,会发生一些奇怪的事情。

public class PositionTests extends TestCase {

    private Position posOne;
    private Position posTwo;
    private Position posThree;

    public PositionTests() {
        posOne = new Position(7, 6);
        posTwo = new Position(12, 7);
        posThree = new Position(7, 6);
    }

    public void testCreationX() {
        assertEquals(posOne.getX(), (Integer) 7);
    }

    public void testCreationY() {
        assertEquals(posOne.getY(), (Integer) 6);
    }

    public void testEquality() {
        // System.out.println("p1.e(p3): " + posOne.equals(posThree));
        // System.out.println("p3.e(p1): " + posThree.equals(posOne));
        //assertEquals(posOne, posThree);
        assertEquals(posThree, posOne);
    }

    public void testInequality() {
        assertFalse(posOne.equals(posTwo));
    }

    public void testXEquality() {
        assertEquals(posOne.getX(), posThree.getX());
    }

    public void testYEquality() {
        assertEquals(posOne.getY(), posThree.getY());
    }

    public void testSymmTrue() {
        assertTrue(posOne.equals(posThree) == posThree.equals(posOne));
    }

    public void testSymmFalse() {
        assertTrue(posOne.equals(posTwo) == posThree.equals(posTwo));
    }

    public void testHashSetSame() {
        Set<Position> hSet = new HashSet<Position>();
        hSet.add(posOne);
        hSet.add(posThree);
        hSet.add(posTwo);
        hSet.add(posOne);
        hSet.add(posOne);
        hSet.add(posOne);
        assertTrue(hSet.size() == 3);
    }

    public void testListContainsSuccess() {
        List<Position> pList = new ArrayList<Position>();
        pList.add(posOne);
        pList.add(posTwo);
        assertTrue(pList.contains(posOne));
    }

    public void testListContainsSuccessDiff() {
        List<Position> pList = new ArrayList<Position>();
        pList.add(posOne);
        pList.add(posTwo);
        // System.out.println(pList);
        // System.out.println(posThree);
        Boolean b = pList.contains(posThree);
        System.out.println("contains: " + b);
        assertTrue(pList.contains(posThree));
    }

    public void testListContainsFail() {
        List<Position> pList = new ArrayList<Position>();
        pList.add(posOne);
        pList.add(posThree);
        assertFalse(pList.contains(posTwo));
    }

}

测试的相关输出如下:

    [junit] ------------- Standard Output ---------------
    [junit] JUnit version is: 3.8.2
    [junit] contains: false
    [junit] (7, 6).equals((7, 6)): true
    [junit] (7, 6).equals((7, 6)): true
    [junit] (7, 6).equals((12, 7)): false
    [junit] (7, 6).equals((12, 7)): false
    [junit] (7, 6).equals((12, 7)): false
    [junit] (7, 3).equals((7, 4)): false
    [junit] ------------- ---------------- ---------------
    [junit] 
    [junit] Testcase: testListContainsSuccessDiff took 0.005 sec
    [junit]     FAILED
    [junit] null
    [junit] junit.framework.AssertionFailedError
    [junit]     at com.group7.dragonwars.tests.PositionTests.testListContainsSuccessDiff(PositionTests.java:92)
    [junit] 
    [junit] Testcase: testListContainsFail took 0 sec
    [junit] Testcase: testYEquality took 0 sec
    [junit] Testcase: testSymmTrue took 0.014 sec
    [junit] Testcase: testSymmFalse took 0.001 sec
    [junit] Testcase: testHashSetSame took 0 sec
    [junit] Testcase: testListContainsSuccess took 0 sec
    [junit] Testcase: testCreationY took 0 sec
    [junit] Testcase: testEquality took 0.001 sec
    [junit]     FAILED
    [junit] expected:<(7, 6)> but was:<(7, 6)>
    [junit] junit.framework.AssertionFailedError: expected:<(7, 6)> but was:<(7, 6)>
    [junit]     at com.group7.dragonwars.tests.PositionTests.testEquality(PositionTests.java:43)
    [junit] 
    [junit] Testcase: testInequality took 0.001 sec
    [junit] Testcase: testXEquality took 0 sec
    [junit] Testcase: testCreationX took 0 sec
    [junit] Test com.group7.dragonwars.tests.AllTests FAILED

现在发布了我所有的相关代码和测试结果,我的问题是为什么 assertEquals(posOne, posThree) 以及对 contains() 的调用会失败?正如您在测试输出顶部看到的那样,.equals() 返回 true。我很困惑为什么这些失败。在我的整个程序中,我不得不使用手动列表遍历和手动调用 equals() 来检查列表成员,但为什么?List 的文档说

Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)). 

然而,.contains()失败了。什么……?

4

2 回答 2

2

如果您@Override向 equals() 方法添加注释,您将看到问题。参数类型必须是Object,不是Position

@Override
public boolean equals(Object other) {

另外,里面有错别字Pair.hashCode()

    int hashFirst = left != null ? left.hashCode() : 0;
    int hashSecond = left != null ? right.hashCode() : 0;
                     ^^^^^
于 2013-04-05T15:52:20.523 回答
0

您希望 Position 和 Pair 上的 equals 采用 Object —— 您只是用采用 Pair 的声明重载它。

您在 Pair 上的 hashCode 实现也很奇怪 :) 也许使用 Apache EqualsBuilder 和 HashBuilder 类?

相关javadoc:http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object)

于 2013-04-05T15:54:03.707 回答