美文网首页
Chapter 3. Methods Common to All

Chapter 3. Methods Common to All

作者: cuzz_ | 来源:发表于2018-05-23 14:32 被阅读0次

ITEM 10: Obey the general contract when overriding equals

In summary, don’t override the equals method unless you have to: in many cases, the implementation inherited from Object does exactly what you want. If you do override equals , make sure to compare all of the class’s significant fields and to compare them in a manner that preserves all five provisions of the equals contract.

ALWAYS OVERRIDE hashcode WHEN YOU OVERRIDE equals

  • One-line hashCode method - mediocre performance
@Override 
public int hashCode() {
    return Objects.hash(lineNum, prefix, areaCode);
}

If a class is immutable and the cost of computing the hash code is significant, you might consider caching the hash code in the object rather than recalculating it each time it is requested. Otherwise, you might choose to lazily initialize the hash code the first time hash-Code is invoked.

  • hashCode method with lazily initialized cached hash code
private int hashCode; // Automatically initialized to 0
@Override 
public int hashCode() {
    int result = hashCode;
    if (result == 0) {
    result = Short.hashCode(areaCode); 
    result = 31 * result + Short.hashCode(prefix);
    result = 31 * result + Short.hashCode(lineNum);
    hashCode = result;
    }
return result;
}
  • Do not be tempted to exclude significant fields from the hash code computation to improve performance.
  • Don’t provide a detailed specification for the value returned by hashCode , so clients can’t reasonably depend on it; this gives you the flexibility to change it.

ITEM 12: Always override toString

ITEM 13: Override clone judiciously

  • in practice, a class implementing Cloneable is expected to provide a properly functioning public clone method.
x.clone() != x  // true
x.clone().getClass() == x.getClass()  // true
x.clone().equals(x)  // true
  • immutable classes should never provide a clone method
  • In effect, the clone method
    functions as a constructor; you must ensure that it does no harm to the original object and that it properly establishes invariants on the clone
  • the Cloneable architecture is incompatible with normal use of final fields referring to mutable objects
  • A better approach to object copying is to provide a copy constructor or copy factory.

Implementing comparale

Unlike the other methods discussed in this chapter, the compareTo method is not declared in Object. Rather, it is the sole method in comparable Comparable inteface. It is similer in charater to Object's equals method, except that is permits order comparisons in addition to simple equality comparisons, and it is generic. By implementing Comparable, a class indicates that its instance have a natural ordering. Sorting an array of objects that implement Comparable is as simple as this:

Arrays.sort(a);

It is similarly easy to serch, compute extreme values, and maintain automatically sorted collections of Comparable Objects. For example, the following program, which relies on the face that String implements Comparable, prints an alphabetized list of its command-line arguments whit duplicates eliminated:

public class WordList{
    public static void main(String[] args) {
        Set<String> s = new TreeSet<>();
        Collections.addAll(s, args);
        System.out.println(s);
    }
}

By implements Comparable, you allow your class to interoperate whit all of the many generic algorithms and collection implementations that depend on this interface. You gain a tremendous amount of power for a small amount of effort. Virtually all of the value classes in the Java platform libraries, as well as all enum types, implement Comparable. If you are writing a value class with an obvious natural ordering, such as alphabetical order, numerical order, or chronological order, you should implement the Comparable interface:

public interface Comparable<T> {
    int comparaTo(T t);
}

The general contract of the comparaTo method is similar to that of equals:
Comparaes this object whit the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

Throws classCastException if the specified object's type prevents it from being compared to this object.

In the following descripetion, the nataion sgn(expression) designates the mathematical siginum function, which is defined to -1, 0, 1, according to whether the value of expression is negative, zero, or positive/

  • The implementor must ensure that sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.(This implies that x.compareTo(y) must thorw an exception if and only if y.compareTo(x) throws an exception.)
  • The implementtor must also ensure that the relation is transitive:(x.compareTo(y) > 0 && y.compareTo(z)) > 0 implies x.compareTo(z) > 0.
  • Finally, the iplementor must ensure that x.compareTo(y) == 0 implies that sgn(x.compareTo(z)) == syn(y.compareTo(z)), for all z.
  • It is Strongly recommended, but not requured, that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Node: This class has a natural ordering that is inconsistent with equals."

Writing a compareTo method is similar to writing an equals method, but there are a few key differents, Because the Comparable interface is parameterized, the compareTo method is statically typed, so you don't need to type check or cast its argument.

Use of the relational operators <and> in compareTo methods is verbose and error-prone and no longer recommended.

  • Multiply-field Comparable with primitive fields
public int compareTo(PhoneNumber pn) {
    int result = Short.compare(areaCode, pn.areaCode);
    if (result == 0) {
        result = Short.compare(prefix, pn.prefix);
        if (reuslt == 0) {
            result = Short.compare(lineNum, pn.lineNum);
        }   
    }
}
  • Comparable with comparator construction methods
private static final Comparator<PhoneNumber> COMPARATOR = 
    comparingInt((PhoneNumber pn) -> pn.areaCode) 
    .thenComparingInt(pn -> pn.prefix)
    .thenComparingInt(pn -> pn.lineNum);

    public int compareTo(PhoneNumber pn) {
        return COMPARATOR.compare(this, pn);
    }

Occasionally you may seecompareTo or compare methods that rely on the fact that the difference between two values is negative if the first value is less than second, zero if the two values are equals, and postive if the first value is greater. Here is an example:

  • BROKEN difference-based comparator-violates transitivity!
static Comparator<Object> hashCodeOrder = new Comparator<>(){
    public int compare(Object o1, Object o2) {
    return o1.hashCode() - o2.hashCode();
    }
};
  • Comparator based on static compare method
static Comparator<Object> hashCodeOrder = new Comparator<>(){
    public int compare(Object o1, Object o2) {
    return Integer.compare(o1.hashCode(), o2.hashCode());
    }
};
  • Comparator based on Comparator construction method
static Comparator<Object> hashCodeOrder =
Comparator.comparingInt(o -> o.hashCode());

In summary, whenever you implements a value class that has a sensible ordering, you should hava the class implement the Comparable interface so that its instances can be easily sored, serached, and used in comparison-based collections. When comparing field values in the implementations of the compareTo methods, avoid the use of the <and> operators. Instead, use the static compare methods in the boxed primitive classes or the comparator constructtion methods in the Comparator interface.

相关文章

网友评论

      本文标题:Chapter 3. Methods Common to All

      本文链接:https://www.haomeiwen.com/subject/csyadftx.html