This document discusses effective practices for overriding common object methods like equals, hashCode, toString, and clone in Java. It provides guidelines on when each method should be overridden to obey general contracts and ensure proper functioning with collections and other classes. Key points covered include always overriding equals and hashCode together, following specific rules when overriding equals, and cloning objects judiciously by implementing Cloneable and providing either shallow or deep copies.
The Art Pastor's Guide to Sabbath | Steve Thomason
Joshua bloch effect java chapter 3
1. Methods Common to all
objects
Reference :- joshua bloch effective java book
. -kamal mukkamala
2. History
Joshua Bloch
He led the design and implementation
of numerous Java platform features,
including the Java Collections
Framework, the java.math package,
and the assert mechanism.
Twitter :- @joshbloch
Source:- Google images
3. History
Rohit vaidya
Link to his session presentation :-
http://rohitvvv.info/
Twitter :- @rohit_elan
Source:- Twitter
4. Parent of all our classes.
Object Class :-
Although Object is a concrete class, it is designed primarily for
extension. All of its nonfinal methods (equals, hashCode, toString,
clone, and finalize) have explicit general contracts because they are
designed to be overridden. It is the responsibility of any class
overriding these methods to obey their general contracts; failure to do
so will prevent other classes that depend on the contracts (such
asHashMap and HashSet) from functioning properly in conjunction with
the class.
5. Item 8: Obey the
general contract
when overriding
equals
6. Equals method....
What if you don’t override...?
In that case each instance of object is equal to itself only.
public boolean equals(Object obj)
{
return (this == obj);
}
7. Conditions for not overriding equals method.
• Each Instance of the class is inherently unique.
• You don’t care whether the class provides logical equality or not.
• A super class has already overridden equals, and the super class
behavior is ok for this class.
• The class private or package-private, and you are certain that its equals
method will never be invoked
8. So when is it appropriate to override equals...
"When class has a notation of logical equality that differs from mere object identity,
and a superclass has not yet already overridden it equals to implement desired
behavior. "
9. Rules to follow while overriding...
Reflexive :- For any non-final value x, x.equals(x) must return true.
Symmetric :- For any non-null reference values x and y, x.equals(y) must return true if and only
y.equals(x) return true.
Transitive :- For any non-null reference values x,y and z, x.equals(y) must return true and y.equals(x)
return true, then x.equals(z) must return true.
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 object is
modified.
For any null reference value x, x.equals(null) must return false.
10. Symmetry
"Once you have violated the equals contract, you simply don’t know how other
objects will behave when confronted with your object."
11. How to get a high quality equals method.
1. Use the == operator to check if the argument is a reference to this object.
2. Use the instanceof operator to check if the argument has the correct type.
3. Cast the argument to the correct type.
4. For each “significant” field in the class, check if that field of the argument matches
the corresponding field of this object.
5. When you are finished writing your equals method, ask yourself three questions: Is
it symmetric? Is it transitive? Is it consistent?
13. What if you din't override hashCode
"Failure to override hashCode will prevent your class from functioning properly in
conjunction with all hash based collections, including HashMap, HashSet and
HashTable."
14. General contracts to follow while overriding...
• Whenever it is invoked on the same object more than once during an execution of a Java application, the
hashCode method must consistently return the same integer, provided no information used in equals
comparisons on the object is modified. This integer need not remain consistent from one execution of an
application to another execution of the same application.
• If two objects are equal according to the equals(Object) method, then calling the hashCode method on each
of the two objects must produce the same integer result.
• It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then
calling the hashCode method on each of the two objects must produce distinct integer results. However, the
programmer should be aware that producing distinct integer results for unequal objects may improve the
performance of hash tables.
15. When hashCode is not overrided...
"When you don't provide hashcode implementation Hash based collections (map, set)
uses system generated hashcode to store and retrieve, which happens to be different
even when two objects have the same attribute.."
16. Recipe to produce hash values
1. Store some constant nonzero value, say, 17, in an int variable called result.
2. For each significant field f in your object (each field taken into account by the
equals method, that is), do the following:
1. Compute an int hash code c for the field:
1. If the field is a boolean, compute (f ? 1 : 0).
2. If the field is a byte, char, short, or int, compute (int) f.
3. If the field is a long, compute (int) (f ^ (f >>> 32)).
4. If the field is a float, compute Float.floatToIntBits(f).
5. If the field is a double, compute Double.doubleToLongBits(f), and then hash the resulting long as in step 2.a.iii.
17. 6. If the field is an object reference and this class’s equals method compares the
field by recursively invoking equals, recursively invoke hashCode on the field. If a more
complex comparison is required, compute a “canonical representation” for this field
and invoke hashCode on the canonical representation. If the value of the field is null,
return 0 (or some other constant, but 0 is traditional).
7.If the field is an array, treat it as if each element were a separate field. That is,
compute a hash code for each significant element by applying these rules recursively,
and combine these values per step 2.b. If every element in an array field is significant,
you can use one of the Arrays.hashCode methods added in release 1.5.
2.Combine the hash code c computed in step 2.a into result
18. 3.Return result.
4.When you are finished writing the hashCode method, ask yourself whether equal
instances have equal hash codes. Write unit tests to verify your intuition! If equal
instances have unequal hash codes, figure out why and fix the problem.
20. toString
The toString method for class Object returns a string consisting of the name of the
class of which the object is an instance, the at-sign character `@', and the unsigned
hexadecimal representation of the hash code of the object. In other words,
this method returns a string equal to the value of:
getClass().getName() + '@' + Integer.toHexString(hashCode())
22. What is clone()...
"The clone() is a tricky method from java.lang.Object class.The intention of the clone()
method is simple, to provide a cloning mechanism, but somehow it's implementation
became tricky and has been widely criticized from a long time. "
23. What is Cloneable interface...
"The Cloneable interface was intended as a mixin interface for objects to advertise
that they permit cloning. Unfortunately, it fails to serve this purpose. Its primary flaw is
that it lacks a clone method, and Object’s clone method is protected. You cannot,
without resorting to reflection , invoke the clonemethod on an object merely because it
implements Cloneable. Even a reflective invocation may fail, as there is no guarantee
that the object has an accessible clonemethod."
24. What does Cloneable do...?
"It determines the behavior of Object’s protected clone implementation: if a class
implementsCloneable, Object’s clone method returns a field-by-field copy of the
object; otherwise it throws CloneNotSupportedException. "
25. Clone method contracts...
Creates and returns a copy of this object. The precise meaning of “copy” may depend
on the class of the object. The general intent is that, for any object x, the expression
x.clone() != x
will be true, and the expression
x.clone().getClass() == x.getClass()
will be true, but these are not absolute requirements. While it is typically the case that
x.clone().equals(x)
will be true,
26. Things to remember...
1.The clone() method is used to create a copy of an object in Java. In order to use clone() method, class must
implement java.lang.Cloneable interface and override protected clone() method from java.lang.Object.
A call to clone() method will result in CloneNotSupportedException if that class doesn't implement Cloneable
interface
2.No constructor is called during cloning of Object in Java.
3.Default implementation of clone() method in Java provides "shallow copy" of object, because it creates copy
of Object by creating new instance and then copying content by assignment, which means if your class contains
a mutable field, then both original object and clone will refer to same internal object. This can be dangerous
because any change made on that mutable field will reflect in both original and copy object. In order to avoid
this, override clone() method to provide the deep copy of an object.
27. 4.By convention, clone of an instance should be obtained by calling super.clone()
method, this will help to preserve invariant of object created by clone() method i.e.
clone != original and clone.getClass() == original.getClass(). Though these are not
absolute requirement as mentioned in Javadoc.
5.A shallow copy of an instance is fine, until it only contains primitives and Immutable
objects, otherwise, you need to modify one or more mutable fields of object returned
by super.clone(), before returning it to caller.