equals - symmetric contract in java seems to be giving issue

320 Views Asked by At

I'm testing the symmetric contract of object Equals method mentioned in the Effective Java 2nd Edition Book.

Symmetric: For any non-null reference values x and y, x.equals(y) must return true if and only if y.equals(x) returns true.

Can you explain me - why list.contains(s) still returns false in the below code.

public final class CaseInsensitiveString {
    private final String s;

    public CaseInsensitiveString(String s) {
        if (s == null)
            throw new NullPointerException();
        this.s = s;
    }

    // Broken - violates symmetry!
    /*
     * @Override public boolean equals(Object o) {
     *  if (o instanceof  CaseInsensitiveString)
     *   return s.equalsIgnoreCase(((CaseInsensitiveString) o).s); 
     *   if (o instanceof String) // One-way  interoperability
     *    return s.equalsIgnoreCase((String) o); return false; 
     *    }
     */

    @Override
    public boolean equals(Object o) {
        return o instanceof CaseInsensitiveString
                && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
    }

    public int hashcode() {
        return 0;
    }

    public static void main(String[] args) {

        CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
        String s = "polish";
        // System.out.println(cis.equals(s));
        // System.out.println(s.equals(cis));
        List<CaseInsensitiveString> list = new ArrayList<CaseInsensitiveString>();
        list.add(cis);
        System.out.println(list.contains(s));
    }

}
2

There are 2 best solutions below

4
On BEST ANSWER

The list contains a single instance of CaseInsensitiveString. s is a String instance, which cannot be equal to any CaseInsensitiveString since o instanceof CaseInsensitiveString which appears in the equals method will return false.

If you test your code with two instances of CaseInsensitiveString that are constructed by strings containing the same values in different cases, you'll see that the contains call will return true:

CaseInsensitiveString titleCase = new CaseInsensitiveString("Polish");
CaseInsensitiveString lowerCase = new CaseInsensitiveString("polish"); // Here!
List<CaseInsensitiveString> list = new ArrayList<CaseInsensitiveString>();
list.add(titleCase);
System.out.println(list.contains(lowerCase)); // prints true
0
On

Because s is a String so o instanceof CaseInsensitiveString will return false.