什么是用于equals()方法的字段的"规范表示"(Joshua Bloch)

Ada*_*dam 7 java equals

在第3章第8项中:

public final class CaseInsensitiveString {
    private final String s;

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

    @Override public boolean equals(Object o) {
        return o instanceof CaseInsensitiveString &&
            ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
    }
    // remainder omitted
}
Run Code Online (Sandbox Code Playgroud)

在描述了该equals()方法的问题之后,他继续在比较字段的上下文中讨论这个类.

对于某些类,例如上面的CaseInsensitiveString,字段比较比简单的相等测试更复杂.如果是这种情况,您可能希望存储该字段的规范形式,因此该equals()方法可以对这些规范形式进行廉价的精确比较,而不是更昂贵的不精确比较.这种技术最适合不可变类; 如果对象可以更改,则必须使规范形式保持最新.

所以我的问题(我仔细检查了'规范'意味着什么):Bloch在谈论什么?规范形式是什么?我已经准备好被告知答案很简单(大概是他的编辑会告诉他增加更多),但我想看到其他人这么说.

他还在hashCode()下一个项目9中提到了同样的事情.

为了在上下文中给出它,他还讨论了该equals()方法的错误版本CaseInsensitiveString:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

Ser*_*zov 6

您应该为其添加另一个final字段和存储值s.toUpperCase().这个新领域将是规范表示 s领域.方法的新实现equals()(参见下面的代码)将更便宜.此方法仅适用于不可变类.

hashCode()如果你覆盖,你不应该忘记覆盖的另一点equals().

public final class CaseInsensitiveString {

  private final String s;
  private final String sForEquals; //field added for simplifier equals method

  public CaseInsensitiveString(String s) {
      if (s == null) {
          throw new IllegalArgumentException(); //NullPointerException() - bad practice
      }
      this.s = s;
      this.sForEquals = s.toUpperCase();
  }

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

  @Override
  public int hashCode(){
      return sForEquals.hashCode();
  }
  // remainder omitted
}
Run Code Online (Sandbox Code Playgroud)