How do you come up with a hash function for a generic object? There is the constraint that two objects need to have the same hash value if they are "equal" as defined by the user. How does Java accomplish this?
I just found the answer to my own question. The way Java does it is that it defines a hashCode for every object and by default the hashCode for two objects are the same iff the two objects are the same in memory. So when the client of the hashtable overrides the equals() method for an object, he should also override the method that computes hashcode such that if a.equals(b) is true, then a.hashCode() must also equal b.hashCode(). This way, it is assured that equal objects have the same hashcode.
First, basically you define the hash function of a class by overriding the hashCode() method. The Javadoc states:
The general contract of hashCode is:
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.
So the more important question is: What makes two of your objects equal? Or vice versa: What properties make your objects unique? If you have an answer to that, create an equals() method that compares all of the properties and returns true if they're all the same and false otherwise.
The hashCode() method is a bit more involved, I would suggest that you do not create it yourself but let your IDE do it. In Eclipse, you can select Source and then Generate hashCode() and equals() from the menu. This also guarantees that the requirements from above hold.
Here is a small (and simplified) example where the two methods have been generated using Eclipse. Notice that I chose not to include the city property since the zipCode already uniquely identifies the city within a country.
public class Address {
private String streetAndNumber;
private String zipCode;
private String city;
private String country;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((country == null) ? 0 : country.hashCode());
result = prime * result
+ ((streetAndNumber == null) ? 0 : streetAndNumber.hashCode());
result = prime * result + ((zipCode == null) ? 0 : zipCode.hashCode());
return result;
}
#Override
public boolean equals(final Object obj) {
if(this == obj)
return true;
if(obj == null)
return false;
if(!(obj instanceof Address))
return false;
final Address other = (Address) obj;
if(country == null) {
if(other.country != null)
return false;
}
else if(!country.equals(other.country))
return false;
if(streetAndNumber == null) {
if(other.streetAndNumber != null)
return false;
}
else if(!streetAndNumber.equals(other.streetAndNumber))
return false;
if(zipCode == null) {
if(other.zipCode != null)
return false;
}
else if(!zipCode.equals(other.zipCode))
return false;
return true;
}
}
Java doesn't do that. If the hashCode() and equals() are not explicitly implemented, JVM will generate different hashCodes for meaningfully equal instances. You can check Effective Java by Joshua Bloch. It's really helpful.
Several options:
read Effective Java, by Joshua Bloch. It contains a good algorithm for hash codes
let your IDE generate the hashCode method
Java SE 7 and greater: use Objects.hash
The class java.lang.Object cheats. It defines equality (as is determined by equals) as being object identity (as can be determined by ==). So, unless you override equals in your subclass, two instances of your class are "equal", if they happen to be the same object.
The associated hash code for this is implemented by the system function System.identityHashCode (which is no longer really based on object addresses -- was it ever? -- but can be thought of as being implemented this way).
If you override equals, then this implementation of hashCode no longer makes sense.
Consider the following example:
class Identifier {
private final int lower;
private final int upper;
public boolean equals(Object any) {
if (any == this) return true;
else if (!(any instanceof Identifier)) return false;
else {
final Identifier id = (Identifier)any;
return lower == id.lower && upper == id.upper;
}
}
}
Two instances of this class are considered equal, if their "lower" and "upper" members have the same values. Since equality is now determined by object members, we need to define hashCode in a compatible way.
public int hashCode() {
return lower * 31 + upper; // possible implementation, maybe not too sophisticated though
}
As you can see, we use the same fields in hashCode which we also use when we determine equality. It is generally a good idea to base the hash code on all members, which are also considered when comparing for equality.
Consider this example instead:
class EmailAddress {
private final String mailbox;
private final String displayName;
public boolean equals(Object any) {
if (any == this) return true;
else if (!(any instanceof EmailAddress)) return false;
else {
final EmailAddress id = (EmailAddress)any;
return mailbox.equals(id.mailbox);
}
}
}
Since here, equality is only determined by the mailbox member, the hash code should also only be based on that member:
public int hashCode() {
return mailbox.hashCode();
}
Hashing of an object is established by overriding hashCode() method, which the developer can override.
Java uses prime numbers in the default hashcode calculation.
If the equals() and hashCode() method aren't implemented, the JVM will generate hashcode implicitly for the object (for Serializable classes, a serialVersionUID is generated).
Related
Just to start off here, this is homework/a lab and I'm looking for advice. I am developing a very small program that is essentially a counter with a min/max value constraint and a method that pushes the value up and another that rolls the value back to zero 0. So, the private data fields I have for my Counter class are:
private int minimum;
private int maximum;
private int currentValue;
The trouble I am having here is with a method that compares my Counter Class to another theoretical object based off the same class. In this case, we're looking to see that the data fields between the two objects are the same. I have researched several ways of doing this including using reflections and the famous EqualsBuilder, but am having trouble implementing each.
Here's the code that they've given me.
public boolean equals(Object otherObject)
{
boolean result = true;
if (otherObject instanceof Counter)
{
}
return result;
}
Assuming your equals method is in the Counter class, it has access to all the private members of that class, even if they are members of a different instance of that class.
public boolean equals(Object otherObject)
{
if (otherObject instanceof Counter)
{
Counter ocounter = (Counter) otherObject;
if (this.minimum != ocounter.minimum)
return false;
...
} else {
return false;
}
return true;
}
Implementing the equals-method can be a real pain, especially if you have a lot of properties in your class.
The JavaDoc for the equals-method states
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
And, if you check the JavaDoc for the hashCode-method.
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(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.
Therefore, it is typically recommended that you implement both methods (equals and hashCode). The following shows one way of doing this that is based on the java.util.Objects-class that came with Java 7. The method Objects.equals(Object, Object) handles null checks which makes the code simpler and easier to read. Furthermore, the hash-method is a convenient way of creating values that can be used with hashCode.
So, to answer your question. In order to access the attributes of your other object, simply perform a type cast. After that you can access the other object's private properties. But, remember to always do this after you have checked the type using instanceof.
#Override
public boolean equals(Object other) {
if (other instanceof Counter) { // Always check the type to be safe
// Cast to a Counter-object
final Counter c = (Counter) other;
// Now, you can access the private properties of the other object
return Objects.equals(minimum, c.minimum) &&
Objects.equals(maximum, c.maximum) &&
Objects.equals(currentValue, c.currentValue);
}
return false; // If it is not the same type, always return false
}
#Override
public int hashCode() {
return Objects.hash(currentValue, maximum, minimum);
}
As equals is a method of Counter, you can access all the private fields of Counter, so you can do something like this:
if (otherObject instanceof Counter)
{
if (this.minimum != ((Counter) otherObject).minimum) {
result = false;
}
// [...]
}
Assuming your class is called Counter and you created getters for all the private fields (that you should do):
#Override
public boolean equals(Object other) {
boolean result = false;
if (other instanceof Counter) {
Counter c= (Counter) other;
result = (this.getMinimum() == that.getMinimum() &&
this.getMaximum() == that.getMaximum() &&
this.getCurrentValue() == that.getCurrentValue());
}
return result;
}
I have made a class called Coordinates which simply holds some x and y integers. I want to use this as a key for a HashMap.
However, I noticed that when you create two different instances of Coordinates with the same x and y values, they are used as different keys by the hash map. That is, you can put two entries even though both of them have the same coordinates.
I have overriden equals():
public boolean equals(Object obj) {
if (!(obj instanceof Coord)) {
return false;
}else if (obj == this) {
return true;
}
Coord other = (Coord)obj;
return (x == other.x && y == other.y);
}
But the HashMap still uses the two instances as if they were different keys. What do I do?
And I know I could use an integer array of two elements instead. But I want to use this class.
You need to override hashCode. Java 7 provides a utility method for this.
#Override
public int hashCode() {
return Objects.hash(x, y);
}
You should also override hashCode() so that two equal instances have the same hashCode(). E.g.:
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
Note that it is not strictly required for two instances that are not equal to have different hash codes, but the less collisions you have, the better performance you'll get from you HashMap.
A hash map uses the hashCode method of objects to determine which bucket to put the object into.
If your object doesn't implement hashCode, it inherits the default implementation from Object. From the docs:
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
As such, each object will appear to be distinct.
Note that different objects may return the same hashCode.
That's called a collision.
When that happens,
then in addition to the hashCode,
the hash map implementation will use the equals method to determine if two objects are equal.
Note that most IDE offer to generate the equals and hashCode methods from the fields defined in your class. In fact, IntelliJ encourages to define these two methods at the same time. For good reason. These two methods are intimately related,
and whenever you change one of them, or implement one of them, or override one of them,
you must review (and most probably change) the other one too.
The methods in this class are 100% generated code (by IntelliJ):
class Coord {
private int x;
private int y;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Coord coord = (Coord) o;
if (x != coord.x) return false;
if (y != coord.y) return false;
return true;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
You probably did not override the hashCode method. Why is that required ? To answer this, you must understand how an hashtable works.
An hashtable is basically an array of linkedlists. Each bucket in the array corresponds to a particular value of hashCode % numberOfBuckets. All the objects with the same hashCode % numberOfBuckets will be stored within a linkedlist in the associated bucket and will be recognized (during the lookup for instance) basing on their equals method. Therefore, the exact specification is a.hashCode() != b.hashCode() => !a.equals(b) which is equivalent to a.equals(b) => a.hashCode() == b.hashCode().
If you use the default implementation of hashCode, which is based on the reference, then two objects that are equal but have a different reference (and so, most probably, a different hashCode) will be stored in a different bucket, resulting in a duplicate key.
I need to implement the equals method in some class A. Class A has an orderer collection of Enum type, and the behaviour I want to achive is that equals returns true for two instances of Class A that have exactly the same Enum values in the collection (in exactly the same positions of the collection).
As I'm new to java, I'm having problems with this, and I dont know how to properly implement equals or the hashcode methods, so any help would be good :)
If you're using eclipse (netbeans has similar features, as do most java IDEs), you can simply got to the "Source" menu, and choose "Generate hashcode() and equals()". Then you select the fields you want to be considered (in your case the list of enum values.
That being said, assuming you already have the enum, here's the code that eclipse generated for me. Not that hashcode usually involves a prime number, as well as multiplication and addition. This tends to give you somewhat decent distribution of values.
public class Foo {
private List<FooEnum> enumValues;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((enumValues == null) ? 0 : enumValues.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Foo other = (Foo) obj;
if (enumValues == null) {
if (other.enumValues != null)
return false;
}
else if (!enumValues.equals(other.enumValues))
return false;
return true;
}
}
The overridden equals method will look like this
public boolean equals(Object o) {
if ((o instanceof yourtype) &&
(((yourtype)o).getPropertyToTest() == this.propertyToTest)) {
return true;
}
else {
return false;
}
}
The overridden hashCode method will look like this
public int hashCode() { return anIntRepresentingTheHashCode}
Pulling from the javadocs, your equals method must meet the following criteria:
reflexive - x.equals(x) is true
symmetric - if x.equals(y) then y.equals(x)
transitive - if x.equals(y) and y.equals(z) then x.equals(z)
consistent - if x.equals(y) is true, then it's always true unless the object is modified
null - x.equals(null) is false
Also, if two objects are equal based on the equals method, they must have identical hash codes.
The reverse is not true. If two objects are not equal, they may or may not have identical hash codes
Use EnumSet It retains natural order as per java docs also and it is optimized for Enums only.
The iterator returned by the iteratormethod traverses the elements in their natural order (the order in which the enum constants are declared). The returned iterator is weakly consistent: it will never throw ConcurrentModificationException and it may or may not show the effects of any modifications to the set that occur while the iteration is in progress.
You can use EnumSet as below
import java.util.EnumSet;
public enum Direction {
LEFT,
RIGHT,
ABOVE,
BELOW;
private static EnumSet<Direction> someDirection = EnumSet.of(Direction.LEFT,Direction.RIGHT) ;
}
Now because you are using EnumSet equals and Hashcode method will be provided default from AbstractSet which is parent class of EnumSet
So You don't have to care about them.
I produce a bunch of objects in Java. Each object has attribute area and a set of integers. I want to store those objects for example in a map(keys should be integers in a growing order). Two objects are the same if their area is equal and their sets are the same.
If two objects don't have the same area then there is no need for me to check whether their sets are the same.
What is the best practice for implementing this in Java? How should I compose hash and equal functions?
Here's sample pair of hashCode\equals generated by IDE:
class Sample {
final int area;
final Set<Integer> someData;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Sample sample = (Sample) o;
if (area != sample.area) return false;
if (!someData.equals(sample.someData)) return false;
return true;
}
#Override
public int hashCode() {
int result = area;
result = 31 * result + someData.hashCode();
return result;
}
}
This code assumes someData can't be null -- to simplify things. You can see that equality of types is checked at first, then area equality is checked and then equality of Set<Integer> is checked. Note that built-in equals of Set is used in this -- so you have re-usage of that method. This is idiomatic way to test compound types for equality.
You just need your object to implement the Comparable interface and code your logic in the compareTo method. Here's a good link to help you achieve that.
A rule of thumb is that you should compare all relevant fields in your equals() implementation (fastest first, so compare your areas up front, then the integer sets) and use THE SAME fields in your hashCode(). If in doubt, use Eclipse's Source - Generate hashCode() and equals()... feature (and then fix the equals() code to compare the areas first.)
Just compare their area first in equals (after the == and type check of course), and return false if these differ. If the areas equal, go on and compare the sets.
For implementing equals (and hashCode) in general, here is a relevant thread and a good article (including several further references).
I´ve often found an equals method in different places. What does it actually do? Is it important that we have to have this in every class?
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj == null)
{
return false;
}
if (obj instanceof Contact)
{
Contact other = (Contact)obj;
return other.getFirstName().equals(getFirstName()) &&
other.getLastName().equals(getLastName()) &&
other.getHomePhone().equals(getHomePhone()) &&
other.getCellPhone().equals(getCellPhone());
}
else
{
return false;
}
}
It redefines "equality" of objects.
By default (defined in java.lang.Object), an object is equal to another object only if it is the same instance. But you can provide custom equality logic when you override it.
For example, java.lang.String defines equality by comparing the internal character array. That's why:
String a = new String("a"); //but don't use that in programs, use simply: = "a"
String b = new String("a");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
Even though you may not need to test for equality like that, classes that you use do. For example implementations of List.contains(..) and List.indexOf(..) use .equals(..).
Check the javadoc for the exact contract required by the equals(..) method.
In many cases when overriding equals(..) you also have to override hashCode() (using the same fields). That's also specified in the javadoc.
Different classes have different criteria for what makes 2 objects "equal". Normally, equals() returns true if it is the same Object:
Object a = new Object();
Object b = new Object();
return(a.equals(b));
This will return false, eventhough they are both "Object" classes, they are not the same instance. a.equals(a) will return true.
However, in cases like a String, you can have 2 different instances but String equality is based on the literal characters that make up those Strings:
String a = new String("example");
String b = new String("example");
String c = new String("another");
a.equals(b);
a.equals(c);
These are all different instances of String, but the first equals will return true because they are both "example", but the 2nd will not because "example" isn't "another".
You won't need to override equals() for every class, only when there is a special case for equality, like a class that contains 3 Strings, but only the first String is used for determining equality. In the example you posted, there could have been another field, description which could be different for 2 different "Contacts", but 2 "Contacts" will be considered equal if those 4 criteria match (first/last name, and home/cell phone numbers), while the description matching or not matching doesn't play into whether 2 Contacts are equal.
Aside from everything given by Bozho, there are some additional things to be aware of if overriding equals:
something.equals(null) must always return false - i.e. null is not equal to anything else. This requirement is taken care of in the second if of your code.
if it is true that something == something else, then also something.equals(something else) must also be true. (i.e. identical objects must be equal) The first if of your code takes care of this.
.equals SHOULD be symetric for non-null objects, i.e. a.equals(b) should be the same as b.equals(a). Sometimes, this requirement breaks if you are subclassing and overriding equals in the parent-class and in the subclass. Often equals contains code like if (!getClass().equals(other.getClass())) return false; that at least makes sure that a diffrent object type are not equal with each other.
If you override equals you also MUST override hashCode such that the following expression holds true: if (a.equals(b)) assert a.hashCode() == b.hashCode(). I.e. the hash code of two objects that are equal to each other must be the same. Note that the reverse is not true: two objects that have the same hash code may or may not be equal to each other. Ususally, this requirement is taken care of by deriving the hashCode from the same properties that are used to determine equality of an object.
In your case, the hashCode method could be:
public int hashCode() {
return getFirstName().hashCode() +
getLastName().hashCode() +
getPhoneHome().hashCode() +
getCellPhone().hashCode();
}
If you implement Comparable that compares two objects if they are smaller, larger, or equal to each other, a.compareTo(b) == 0 should be true if and only if a.equalTo(b) == true
In many IDEs (e.g. Eclipse, IntelliJ IDEA, NetBeans) there are features that generate both equals and hashCode for you, thereby sparing you of tedious and possibly error-prone work.
The equals method is used when one wants to know if two objects are equivalent by whatever definition the objects find suitable. For example, for String objects, the equivalence is about whether the two objects represent the same character string. Thus, classes often provide their own implementation of equals that works the way that is natural for that class.
The equals method is different from == in that the latter tests for object identity, that is, whether the objects are the same (which is not necessarily the same as equivalent).
It enables you to re-define which Objects are equal and which not, for example you may define that two Person objects as equal if the Person.ID is the same or if the Weight is equal depending on the logic in your application.
See this: Overriding the java equals() method quirk
By default, the Object class equals method invokes when we do not provide the implementation for our custom class. The Object class equals method compares the object using reference.
i.e. a.equals(a); always returns true.
If we are going to provide our own implementation then we will use certain steps for object equality.
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return
false.
public class ObjectEqualExample{
public static void main(String []args){
Employee e1 = new Employee(1, "A");
Employee e2 = new Employee(1, "A");
// if we are using equals method then It should follow the some properties such as Reflexive, Symmetric, Transitive, and constistent
/*
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return false
*/
System.out.println(e1.equals(e1));
System.out.println(e1.equals(e2));
}
}
class Employee {
private int id;
private String name;
#Override
public String toString() {
return "{id ="+id+", name = "+name+"} ";
}
#Override
public boolean equals(Object o) {
// now check the referenc of both object
if(this == o) return true;
// check the type of class
if(o == null || o.getClass() != this.getClass()) return false;
// now compare the value
Employee employee = (Employee)o;
if(employee.id == this.id && employee.name.equals(this.name)) {
return true;
} else return false;
}
public int hashCode() {
// here we are using id. We can also use other logic such as prime number addition or memory address.
return id;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
One more thing, maps use the equals method to decide if an Object is present as a key. https://docs.oracle.com/javase/8/docs/api/java/util/Map.html