Diogo Santos
Diogo Santos

Reputation: 830

Testing equals method

I am having a weird issue which I am not being able to understand why this happens.

I have this equals method implemented in a DoublyLinkedList generic class:

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

        DoublyLinkedList<E> other = (DoublyLinkedList<E>) obj;

        if (this.size != other.size) {
            return false;
        }

        Iterator<E> iterator = this.iterator();
        Iterator<E> otherIterator = other.iterator();
        while(iterator.hasNext()){       
            if(iterator.next() != otherIterator.next()){
                return false;
            }
        }
        return true;
    }

Testing this method, in a unit test, like this:

@Test
public void testEquals() {
    System.out.println("equals");
    DoublyLinkedList <String> instance1 = new DoublyLinkedList <>(), instance2 = new DoublyLinkedList <>();

    instance1.addLast("Xpto");
    instance1.addLast("Ypto");
    instance1.addLast("Zpto");

    instance2.addLast("Xpto");
    assertFalse("Lists should not be equal", (instance1.equals(instance2)));
    assertFalse("Lists should not be equal", (instance2.equals(instance1)));        
    instance2.addLast("Ypto");
    assertFalse("Lists should not be equal", (instance1.equals(instance2)));
    assertFalse("Lists should not be equal", (instance2.equals(instance1)));
    instance2.addLast("Zpto");
    assertTrue("Lists should be equal", (instance1.equals(instance2)));
    assertTrue("Lists should be equal", (instance2.equals(instance1)));       
}

Gives me that the test passes. However, why does this happen, if I am using !=, instead of equals to compare each iterator's instance, in the first code? Shouldn't it compare the references, and thus fail?

Thanks in advance!

Upvotes: 2

Views: 585

Answers (2)

Makoto
Makoto

Reputation: 106508

Java is interning (or caching) certain references on your behalf. Specifically, if you enter Strings as your type, you're going to run into some curious String interning behavior, in that suddenly, your lists have the same reference of String. This is the only way that == would work on a reference at all - if it were somehow interned or cached and could be referenced.

This is trivial to defeat; if you use values which do not have the ability to be interned or cached, then you'll observe that your test fails.

For example, new BigInteger("100") and new BigInteger("100") are not the same location in memory, and if you put both of those in your list and attempt to compare equivalence, you'll get false.

Upvotes: 2

Grant Foster
Grant Foster

Reputation: 758

That's because they are pointing to the same location in memory.

See: https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634

Upvotes: 1

Related Questions