The theory (for the language lawyers and the mathematically inclined):
equals()
(javadoc) must define an equivalence relation (it must be reflexive, symmetric, and transitive). In addition, it must be consistent (if the objects are not modified, then it must keep returning the same value). Furthermore, o.equals(null)
must always return false.
hashCode()
(javadoc) must also be consistent (if the object is not modified in terms of equals()
, it must keep returning the same value).
The relation between the two methods is:
Whenever a.equals(b)
, then a.hashCode()
must be same as b.hashCode()
.
In practice:
If you override one, then you should override the other.
Use the same set of fields that you use to compute equals()
to compute hashCode()
.
Use the excellent helper classes EqualsBuilder and HashCodeBuilder from the Apache Commons Lang library. An example:
public class Person {
private String name;
private int age;
// ...
@Override
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
append(name).
append(age).
toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
append(age, rhs.age).
isEquals();
}
}
Also remember:
When using a hash-based Collection or Map such as HashSet, LinkedHashSet, HashMap, Hashtable, or WeakHashMap, make sure that the hashCode() of the key objects that you put into the collection never changes while the object is in the collection. The bulletproof way to ensure this is to make your keys immutable, which has also other benefits.
The name reflection is used to describe code which is able to inspect other code in the same system (or itself).
For example, say you have an object of an unknown type in Java, and you would like to call a 'doSomething' method on it if one exists. Java's static typing system isn't really designed to support this unless the object conforms to a known interface, but using reflection, your code can look at the object and find out if it has a method called 'doSomething' and then call it if you want to.
So, to give you a code example of this in Java (imagine the object in question is foo) :
Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);
One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the @Test annotation, and will then call them when running the unit test.
There are some good reflection examples to get you started at http://docs.oracle.com/javase/tutorial/reflect/index.html
And finally, yes, the concepts are pretty much similar in other statically typed languages which support reflection (like C#). In dynamically typed languages, the use case described above is less necessary (since the compiler will allow any method to be called on any object, failing at runtime if it does not exist), but the second case of looking for methods which are marked or work in a certain way is still common.
Update from a comment:
The ability to inspect the code in the system and see object types is
not reflection, but rather Type Introspection. Reflection is then the
ability to make modifications at runtime by making use of
introspection. The distinction is necessary here as some languages
support introspection, but do not support reflection. One such example
is C++
Best Solution
Joshua Bloch says on Effective Java
Let's try to understand it with an example of what would happen if we override
equals()
without overridinghashCode()
and attempt to use aMap
.Say we have a class like this and that two objects of
MyClass
are equal if theirimportantField
is equal (withhashCode()
andequals()
generated by eclipse)Imagine you have this
Override only
equals
If only
equals
is overriden, then when you callmyMap.put(first,someValue)
first will hash to some bucket and when you callmyMap.put(second,someOtherValue)
it will hash to some other bucket (as they have a differenthashCode
). So, although they are equal, as they don't hash to the same bucket, the map can't realize it and both of them stay in the map.Although it is not necessary to override
equals()
if we overridehashCode()
, let's see what would happen in this particular case where we know that two objects ofMyClass
are equal if theirimportantField
is equal but we do not overrideequals()
.Override only
hashCode
If you only override
hashCode
then when you callmyMap.put(first,someValue)
it takes first, calculates itshashCode
and stores it in a given bucket. Then when you callmyMap.put(second,someOtherValue)
it should replace first with second as per the Map Documentation because they are equal (according to the business requirement).But the problem is that equals was not redefined, so when the map hashes
second
and iterates through the bucket looking if there is an objectk
such thatsecond.equals(k)
is true it won't find any assecond.equals(first)
will befalse
.Hope it was clear