Search code examples
javacollectionsoverridingequalsarraydeque

In ArrayDeque containsAll(Collection c), contains(Object o), equals(Object o) give expected but equals(Collection c) gives unexpected result


I have the following "Person" class -

import java.util.Objects;

public class Person implements Comparable<Person> {
    private int id;
    private String name;

    Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }


    @Override
    public int compareTo(Person person) {
        int myReturn = 0;
        int minLength = 0;
        boolean equal = false;
        int id1 = id;
        int id2 = person.id;
        String name1 = name;
        String name2 = person.name;

        if (name1.length() > name2.length()) {
            minLength = name2.length();
        } else if (name1.length() < name2.length()) {
            minLength = name1.length();
        } else {
            minLength = name1.length();
            equal = true;
        }

        if (id1 > id2) {
            myReturn = 1;
        } else if (id1 < id2) {
            myReturn = -1;
        } else {
            int i = 0;
            for (i = 0; i < minLength; i++) {
                if (name1.charAt(i) > name2.charAt(i)) {
                    myReturn = 1;
                    break;
                } else if (name1.charAt(i) < name2.charAt(i)) {
                    myReturn = -1;
                    break;
                } else {
                    continue;
                }
            }
            if(i == minLength) {
                if (equal) {
                    myReturn = 0;
                } else if (name1.length() > minLength) {
                    myReturn = 1;
                } else {
                    myReturn = -1;
                }
            }
        }
        return myReturn;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return id == person.id && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

Now the following codes behave as expected -

Code 1:

/* equals(Object object) - method */
        Person person3 = new Person(2, "Neha");
        Person person4 = new Person(2, "Neha");
        Person person5 = new Person(2, "Sneha");
        System.out.println(person3.equals(person4));
        System.out.println(person3.equals(person5));

Output -

true
false

Code 2:

/* contains(Object object) - method */
        ArrayDeque<Person> arrayDeque13 = new ArrayDeque<>(List.of(
                new Person(99, "Needhi"),
                new Person(12, "Papori"),
                new Person(78, "Pallavi")
        ));
        Person person1 = new Person(12, "Papori");
        Person person2 = new Person(13, "Puja");
        System.out.println(arrayDeque13.contains(person1));
        System.out.println(arrayDeque13.contains(person2));

Output -

true
false

Code 3:

/* containsAll(Collection collection) - method */
        ArrayDeque<Person> arrayDeque14 = new ArrayDeque<>(List.of(
                new Person(3, "Namita"),
                new Person(2, "Mridu"),
                new Person(82, "Priyadarshini"),
                new Person(89, "Tina"),
                new Person(13, "Kajal")
        ));
        ArrayDeque<Person> arrayDeque15 = new ArrayDeque<>(List.of(
                new Person(3, "Namita"),
                new Person(2, "Mridu"),
                new Person(13, "Kajal")
        ));
        ArrayDeque<Person> arrayDeque16 = new ArrayDeque<>(List.of(
                new Person(3, "Namita"),
                new Person(2, "Mridu"),
                new Person(13, "Neha")
        ));
        System.out.println(arrayDeque14.containsAll(arrayDeque15));
        System.out.println(arrayDeque14.containsAll(arrayDeque16));

Output -

true
false

But the following code doesn't behave as expected -

Code 4:

/* equals(Collection collection) - method */
        ArrayDeque<Person> arrayDeque17 = new ArrayDeque<>(List.of(
                new Person(56, "Leena"),
                new Person(66, "Nidhi"),
                new Person(76, "Payal")
        ));
        ArrayDeque<Person> arrayDeque18 = new ArrayDeque<>(List.of(
                new Person(56, "Leena"),
                new Person(66, "Nidhi"),
                new Person(76, "Payal")
        ));
        ArrayDeque<Person> arrayDeque19 = new ArrayDeque<>(List.of(
                new Person(56, "Leena"),
                new Person(66, "Nidhi"),
                new Person(76, "Payel")
        ));
        System.out.println(arrayDeque17.equals(arrayDeque18));
        System.out.println(arrayDeque17.equals(arrayDeque19));

Output -

false
false

Here, I expect first output to be true but it is false

As given in -

https://docs.oracle.com/javase/7/docs/api/java/util/ArrayDeque.html

Methods inherited from interface java.util.Collection
addAll, containsAll, equals, hashCode, removeAll, retainAll

So, where am I going wrong?


Solution

  • As the commenters have already mentioned, ArrayDeque does not implement equals(). If unsure, look at the javadoc and search for "equals". If it's under "Methods inherited from class java.lang.Object" then you know it's using Object's equals implementation:

    enter image description here

    Interfaces cannot have an equals() method implementation since Java does not allow a default equals method. If a class implements multiple interfaces, each containing a default "equals" methods, which one should be used? So it's kind of irrelevant that it is inherited from the Collection interface. Javadoc lists it there because the Collection interface excplicitly defines equals() with a collection-specific javadoc.