使用equalsIgnoreCase覆盖hashCode并重写equals以检查相等性

Jaz*_*zer 9 java overriding equals hashcode

我目前有一个被覆盖的equals(Object)看起来像这样:

@Override
public boolean equals(Object o) {
    if (o == this) return true;
    if (! (o instanceof Player)) return false;
    Player p = (Player) o;
    return getFirstName().equalsIgnoreCase(p.getFirstName()) && 
            getLastName().equalsIgnoreCase(p.getLastName());
}
Run Code Online (Sandbox Code Playgroud)

hashCode()目前看起来像这样:

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + getFirstName().toLowerCase().hashCode();
    result = 31 * result + getLastName().toLowerCase().hashCode();
    return result;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是关于我重写的hashCode()方法.我知道我需要hashCode()为两个对象返回相同的值,如果它们被equals(Object)方法认为是相等的.我的直觉告诉我,有些情况下这个hashCode()会违反合同.

是否有一种可接受的方法在重写的equals(Object)方法中使用equalsIgnoreCase(String)方法并生成不违反合同的哈希码?

RTS*_*lio 5

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + characterwiseCaseNormalize(getFirstName()).hashCode();
    result = 31 * result + characterwiseCaseNormalize(getLastName()).hashCode();
    return result;
}

private static String characterwiseCaseNormalize(String s) {
    StringBuilder sb = new StringBuilder(s);
    for(int i = 0; i < sb.length(); i++) {
        sb.setCharAt(i,Character.toLowerCase(Character.toUpperCase(sb.charAt(i))));
    }
    return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)

这将与定义的 usinghashCode一致。原则上,根据 的合同,这似乎取决于以下情况:equalsequalsIgnoreCaseequalsIgnoreCase

Character.toLowerCase(Character.toUpperCase(c1))==Character.toLowerCase(Character.toUpperCase(c2))
Run Code Online (Sandbox Code Playgroud)

每当

Character.toLowerCase(c1)==Character.toLowerCase(c2).  
Run Code Online (Sandbox Code Playgroud)

我没有证据证明这是真的,但equalsIgnoreCase 的 OpenJDK 实现实际上与此方法一致;它检查相应的字符是否相等,然后检查它们的大写版本是否相等,然后检查大写版本的小写版本是否相等。