`
leonzhx
  • 浏览: 796608 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Item 8: Obey the general contract when overriding equals

阅读更多

1. A value class is simply a class that represents a value, such as Integer or Date. A programmer who compares references to value objects using the equals method expects to find out whether they are logically equivalent, not whether they refer to the same object.

 

2.  Not to override the equals method is the right thing to do if any of the following conditions apply:

    a)  Each instance of the class is inherently unique. (Thread)
    b)  You don’t care whether the class provides a “logical equality” test.(Random)
    c)  A superclass has already overridden equals, and the superclass behavior is appropriate for this class.(AbstractSet, AbstractList, AbstractMap)
    d)  The class is private or package-private, and you are certain that its equals method will never be invoked.
    e)  A class that uses instance control to ensure that at most one object exists with each value.(Enum)

3.  When you override the equals method, you must adhere to its general contract:
    a)  Reflexive: For any non-null reference value x, x.equals(x) must return true.
    b)  Symmetric: For any non-null reference values x and y, x.equals(y) must return true if and only if y.equals(x) returns true.
    c)  Transitive: For any non-null reference values x, y, z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) must return true.
    d)  Consistent: For any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
    e)  For any non-null reference value x, x.equals(null) must return false.

 

4.  Not only is overriding the equals method necessary to satisfy programmer expectations; it enables instances to serve as map keys or set elements with predictable, desirable behavior.

 

5.  There is no way to extend an instantiable class and add a value component while preserving the equals contract. Preserving the equals contract by using a getClass test in place of the instanceof test in the equals method will break Liskov substitution principle.( superclass instance cannot compare with subclass instance) Note that you can add a value component to a subclass of an abstract class without violating the equals contract because it is impossible to create a superclass instance directly.

 

6.  java.sql.Timestamp extends java.util.Date and adds a nanoseconds field. The equals implementation for Timestamp does violate symmetry and can cause erratic behavior if Timestamp and Date objects are used in the same collection or are otherwise intermixed.


7.  Do not write an equals method that depends on unreliable resources. equals methods should perform deterministic computations on memory-resident objects.


8.  java.net.URL’s equals method relies on comparison of the IP addresses of the hosts associated with the URLs. Translating a host name to an IP address can require network access, and it isn’t guaranteed to yield the same results over time. This can cause the URL equals method to violate the Consistency contract.

 

9.  A recipe for a high-quality equals method:
    a)  Use the == operator to check if the argument is a reference to this object for performance optimization.
    b)  Use the instanceof operator to check if the argument has the correct type. (Use an interface if the class implements an interface that refines the equals contract to permit comparisons across classes that implement the interface. Such as Set, List, Map, and Map.Entry.
    c)  Cast the argument to the correct type.
    d)  For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object. (If the type in step b) is an interface, you must access the argument’s fields via interface methods; )
    e)  When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?

 

10.  For primitive fields whose type is not float or double, use the == operator for comparisons; for object reference fields, invoke the equals method recursively; for float fields, use the Float.compare method; and for double fields, use Double.compare.(due to the Float.NaN and -0.0f exception)

 

11.  To avoid the possibility of a NullPointerException, use this idiom to compare such fields:
 

(field == null ? o.field == null : field.equals(o.field))

 

This alternative may be faster if field and o.field are often identical:

(field == o.field || (field != null && field.equals(o.field)))

12.  For best performance, you should first compare fields that are more likely to differ, less expensive to compare, or, ideally, both. If a redundant field amounts to a summary description of the entire object, comparing this field will save you the expense of comparing the actual data if the comparison fails.

 

13.  The File class shouldn’t attempt to equate symbolic links referring to the same file. Thankfully, it doesn’t.

 

14.  Don’t substitute another type for Object in the equals declaration. The problem is that this method does not override Object.equals, whose argument is of type Object, but overloads it instead. 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics