当你覆盖 equals 方法时,你必须遵守它的通用约定之对称性

    科技2022-07-10  108

    摘自Effective Java中文版

    对称性(symmetric):对于任何非空参考值 x 和 y,x.equals(y) 必须在且仅当 y.equals(x) 返回 true 时返回 true。

    看一个重写equals方法的例子。目的是忽略大小写。

    // Broken - violates symmetry! class CaseInsensitiveString { private final String s; public CaseInsensitiveString(String s) { this.s = Objects.requireNonNull(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; } CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); String s = "polish";

    正如预期的那样,cis.equals(s) 返回 true。问题是,虽然 CaseInsensitiveString 中的 equals 方法知道普通字符串,但是 String 中的 equals 方法对不区分大小写的字符串不知情。因此,s.equals(cis) 返回 false,这明显违反了对称性。

    System.out.println(cis.equals(s));//true System.out.println(s.equals(cis));//false

    假设你将不区分大小写的字符串放入集合中:

    List<CaseInsensitiveString> list = new ArrayList<>(); list.add(cis);

    那么list.contains(s)会返回false。

    这是因为List的contains方法的源码是用的传入对象的.equals()方法。即还是s.equals()。所以肯定是false。

    public boolean contains(Object o) { return indexOf(o) >= 0; } /** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }

    比如你用List<String>来比较。

    List<String> list1 = new ArrayList<>(); list1.add(s); System.out.println(list.contains(cis)); //true

     道理同上。

     

     

     

    Processed: 0.012, SQL: 8