[Java study notes] Effective Java (Third Edition) Chapter 3 for all objects that are common methods

10 bar: coverage equals observe common convention when

Without override equals, for each instance of the class is equal only to itself.

  • Each instance of the class is essentially unique.
  • Class does not need to provide a "logical equivalent (logical equality)" test function.
  • Parent has overridden the equals method, and the behavior of the parent class entirely appropriate for this subclass.
  • Class is private or package-level private, and can determine its equals method will never be called.

When do I need to cover the equals method?
  If a class contains a logical concept equal (logical equality) - This concept differs from the object identity (object identity), but the parent class has not rewritten the equals method.

  This is typically used in situations where the value of the class (value classes) of.

When coverage equals method, it must comply with the general specification. Here is the Object class comment in the specification:

  • Reflexivity: x.equals (x) must return true
  • Symmetry: x.equals (y) returns true if and only if y.equals (x) returns true
  • Transitive: if x.equals (y) returns true, y.equals (z) returns true, x.equals (z) must return true
  • Consistency: If the information used in equals comparisons is not modified, the x.equals (y) multiple calls must always return true or consistently return false
  • For any non-null reference x, x.equals (null) must return false

The secret to write a high-quality equals method:

  • == operator to check whether a reference parameter for the object. If so, it returns true.
  • Use instanceof operator to check whether the correct type parameter. If not, false is returned.
  • Converts the parameter to the correct type.
  • For each class key field (attribute), attribute checks whether the parameter corresponding to the object attribute match.
  • For non-base type float or double type, comparing == operator; attribute for the object reference, equals method recursively calls; For float primitive type, use the static method Float.compare (float, float); for double primitive type, using Double.compare (double, double) method.
  • Equals the performance of the method may be affected by the order attribute comparison. For best performance, you should first compare different attributes and most likely overhead is relatively small property.

   For example String example:

public boolean equals(Object anObject) {
    if (this == anObject) { 
        return true;
    }
    if (anObject instanceof String) { 
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

The final caveat:

  • To override hashCode when total coverage equals.
  • Do not try to be too smart to let the equals method.
  • Do not Object object equals declaration substituting other types.

  In short, do not easily override equals, unless forced to. Because in many cases, it inherited from Object achieve exactly what you want.

  If coverage equals method, be sure to compare all the key fields of this class and to ensure compliance with the terms of equals five contracts.

 

11 Section: coverage equals always covered when hashCode

  In each class method override equals, hashCode method need to be rewritten.
  If you do not, your class would violate the common convention hashCode, and this will prevent it set to work in such a HashMap and HashSet.
 

  Object Code conventions content:

  • In the process of execution of the application, if the comparison equals method does not modify any information, repeated calls on an object hashCode method must always return the same value. When the value is returned to the application from another application program may be inconsistent.
  • If two objects according equals (Object) method is relatively equal, then calling the hashCode on the two objects must produce the same integer result.
  • If the two objects are not equal according to the comparison equals (Object) method does not require the call hashCode on each object must produce different results. Generate different results for unequal objects may improve the performance of the hash table (hash tables) of.

    HashCode violation does not cover the above-described second statute: equal objects must have equal hash code (hashCode).

  A good hash method tends to generate unequal hash code is an example of unequal.

  Ideally, the hash code assigned uniformly within the range int set unequal instance hash method. To achieve this ideal situation can be difficult.

 Simple steps:
  1. Declare a variable of type int Result, initialized to the first object is an important property of hash code c, as described in step 2.a calculated above.
  2. For the remaining important properties of the object f, do the following:
    A is a calculated attribute type int f of the hash code C:.
      . I If the property is a primitive type, calculated using Type.hashCode (f) method, wherein type class attribute f corresponding wrapper class.
      ii. If the property is an object reference, and the equals method to compare the properties of this class equals recursively call, then recursively calling the hashCode method.

          If you need more complex comparisons, the computing "paradigm" for this field (canonical representation), and calls on the hashCode paradigm.

          If this field is empty, the 0 (Other constants may be used, but usually indicates 0).
      III. If the property is an array f, of each of the array elements are important as an independent property.

          If the array element is not important, use a constant, it is best not to zero. If all the elements are very important, use Arrays.hashCode method.
    . 2.a in Step B calculated hash code c merged into the following results: result = result + c * 31 is;
  3. Return result value.

example:

// Typical hashCode method
@Override public int hashCode() {
    int result = Short.hashCode(areaCode);
    result = 31 * result + Short.hashCode(prefix);
    result = 31 * result + Short.hashCode(lineNum);
    return result;
}

  After verification finished, ask yourself "is equal instances have equal hash codes."

  In short, whenever coverage equals method must override hashCode, otherwise the program will not run properly.
  May also be utilized AutoValue (google) generated equals and hashCode method, without having to write by hand, you can be tested omitted. IDE portion provide similar functional part.

 

12 Rule: Always cover toString

  Providing good readable toString implementations can make use of this class of systems easier to debug.
  In practical applications, toString method should return all of the information contained in the object of concern. Whether or not the specified format, it should clearly show your intentions in the document.
  Does not make sense when writing toString method in a static class tools, you do not write toString method in most enumerated type.
  Google open source AutoValue toString method will generate for you.

  In short, we want to override toString Object achieve in each class can be instantiated you write, unless already done so in the superclass.

  This will make use of the class easier to debug. toString method should return a succinct about the object, useful description.

 

13 bar: carefully covered clone

  Cloneable interface object is an object as an interface, it allows the cloning of such objects show (clone).
  Cloneable interface class is implemented to provide a function appropriate to the public clone method.

  Suppose you want to implement the Cloneable interface in a class, its parent classes provide well-behaved clone method.

  First call super.clone. The resulting object will be fully functional replica of the original. Any property declared in your class will have the same value of the original property.

  Each attribute if the object contains a reference to the original value or immutable object, the return may be just what you need, in this case, no further processing. (Shallow copy)
 

  Immutable class should never provide a clone method.
  If a clone Simple Object containing a mutable object, the implementation may be displayed in front of catastrophic.

  example:

ublic class Stack {

    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];

        elements[size] = null; // Eliminate obsolete reference
        return result;
    }

    // Ensure space for at least one more element.
    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

  Examples of the above-mentioned desired clone can be made, if only the method returns to super.clone clone () call to the object, then the resulting Stack instance with the correct value in its size attribute,

  However, the original reference elements property Stack Examples same array. Examples of the modification of the original constraints destroy clones, and vice versa.

  You'll soon find that your program produces results meaningless, or NullPointerException is thrown.
 

  In fact, clone method is another constructor, you must ensure that it does not hurt to the original object, and ensure proper constraints created by cloning object.
 Examples of the above-described elements in an array called recursively clone:

// Clone method for class with references to mutable state
@Override public Stack clone() {
    try {
        Stack result = (Stack) super.clone();
        result.elements = elements.clone();
        return result;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}

  Calls on the array of arrays clone returned, type and array types are cloned same compile-time, this is the best habit to copy the array.

  If the elements property is final, the previous solutions will not work, since the clones would be to prohibit attribute is assigned a new value.

  This is a fundamental problem: the same as the sequence of normal use Cloneable architecture and the final attribute reference variable objects are not compatible.
 

  Just call recursively clone method is not always enough.

  For example, a class hash bucket contains an array of points to pass each hash key - the value of the first list is a singly linked list.

  If only clone hash arrays, but as the array reference list as the original object, and prone to clone the original object uncertain behavior. All copies must be separately linked list and each bucket.

  In short, all the realization Cloneable public class should override the clone method, and this method's return type is the class itself.

  This method should first call super.clone, then repair any property in need of restoration.

  Typically, this means copying any files containing internal "deep structure" of variable objects, and with reference to the new object to replace the original point to the object.

  While these internal copy can usually be achieved by recursive calls clone, but this is not always the best method.

  If the class contains only primitive types or references to immutable objects, then it may not be the case of property in need of restoration.

  There are exceptions to this rule, for example, represent a serial number or other unique attribute ID is substantially even or immutable type, also need to be corrected.

  A copy constructor (copy constructor) plant or copy (copy factory) when the copy of the object of a better way.

// Copy constructor
public Yum(Yum yum) { ... };
// Copy factory
public static Yum newInstance(Yum yum) { ... };

  In short, taking into account all the problems associated with the Cloneable interface, the new interface should not inherit it, a new extensible class should not implement it.

  Though implement the Cloneable interface to no harm final class, but should be regarded as performance optimization point of view, only in rare cases is justified (entry 67).

  Typically, copy function preferably provided by a constructor or factory. A notable exception to this rule is an array, which is preferably reproduced by clone method.

 

Article 14: Consider implementing Comparable interface

  Unlike the other methods discussed in this chapter, compareTo method was not declared in the Object class.

  Instead, it is the only method Comparable interface. Comparable interface implemented by, instances of a class that it has a natural order (natural ordering).

  By implementing the Comparable interface, you can make your class with a collection of generic algorithms and all dependent implementations of this interface to interoperate.

  Java platform libraries in almost all classes and all values ​​of enumerated types (Item 34) implement the Comparable interface.

  If you are writing a significant value class natural order (e.g., alphabetical order, numerical order or chronological order), then the interface should implement Comparable:

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

  This object to the specified object to be compared sorted. The return value may be negative integer, zero or a positive integer, corresponding to the object is less than, equal to or greater than the specified object.
  compareTo across different types of objects can not be compared, when comparing different types of objects, throw a ClassCastException.

  Consider BigDecimal class, which is inconsistent with equals compareTo method.

  If you create an empty HashSet instance, and then add new BigDecimal ( "1.0") and new BigDecimal ( "1.00"), the collection will contain two elements,

  Because compared with the equals method, added to two sets of BigDecimal instances are not equal.

  However, if instead of HashSet TreeSet using the same procedure, the set will contain only one element, because compared using compareTo method, two BigDecimal instances are equal.

  In Java 7, static comparison methods are added to the Java class of all packaging. Use relational operators in the process compareTo <and> are tedious and error-prone, is no longer recommended.

  Java 8 in the Comparator interface provides a set of methods comparator, the comparator can be constructed smoothly.

  Many programmers prefer the simplicity of this approach, although it will sacrifice some performance. When using this method, considering the static import using Java, the comparator can be referenced to a static method by which a simple name.

// 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);
}

 

Guess you like

Origin www.cnblogs.com/fyql/p/11401798.html