HashCode implementation for generic objects [duplicate] - java

This question already has answers here:
HashCode for Generic objects in Java
(3 answers)
Closed 4 years ago.
I've a Node class with this parameters:
public class Node < T > {
private T value;
private int priority;
}
I know that I need to override the hashcode method but I don't know how to do it because value is a generic object. I read that it could be done by using the address of the object, but is not recommended because the JVM can change the address of the object during the execution of the program.

You should combine value.hashCode() with the priority value in order to calculate a Node's hashCode().
For example:
#Override
public int hashCode()
{
return 31 * value.hashCode() + priority;
}
This relies on users of your Node class overriding hashCode() in the relevant classes (the classes used as types of Node value).
Note that this is the way JDK collection classes implement hashCode. For example, the default implementation of hashCode() for Sets is the sum of the hashCode()s of the Set's elements.

Related

Why doesn't HashSet maintain uniqueness? [duplicate]

This question already has answers here:
Java HashSet contains duplicates if contained element is modified
(7 answers)
Mutable objects and hashCode
(6 answers)
What happens to the lookup in a Hashmap or Hashset when the objects Hashcode changes
(4 answers)
Java: Modify id that changes hashcode
(1 answer)
mutable fields for objects in a Java Set
(4 answers)
Closed 5 years ago.
Consider the employee class -
public class Employer implements Serializable{
private Long id;
private String name;
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj instanceof Employer) {
Employer employer = (Employer) obj;
if (this.id == employer.id) {
return true;
}
}
return false;
}
//Idea from effective Java : Item 9
#Override
public int hashCode() {
int result = 17;
result = 31 * result + id.hashCode();
//result = 31 * result + name.hashCode();
return result;
}
}
With 2 employee objects created -
Employer employer1 = new Employer();
employer1.setId(10L);
Employer employer2 = new Employer();
employer2.setId(11L);
After adding them to the hashset, the size will be 2.
HashSet internally uses a hashmap to maintain the uniqueness-
private transient HashMap<E,Object> map;
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Now, if I set the id for the second employee to be same as that of the first, i.e-
employer2.setId(10L);
the size still remains 2.
Why is it not 1? Does the in-variants get destroyed?
All hash-based containers, including HashSet<T>, make a very important assumption about hash code of their keys: they assume that hash code never changes while the object is inside the container.
Your code violates this assumption by modifying the instance while it is still in the hash set. There is no practical way for HashSet<T> to react to this change, so you must pick one of two ways to deal with this issue:
Never modify keys of hash-based containers - This is by far the most common approach, often achieved by making hash keys immutable.
Keep track of modifications, and re-hash objects manually - essentially, your code makes sure that all modifications to hash keys happen while they are outside containers: you remove the object from the container, make modifications, and then put it back.
The second approach often becomes a source of maintenance headaches. When you need to keep mutable data in a hash-based container, a good approach is to use only final fields in the computation of your hash code and equality checks. In your example this would mean making id field final, and removing setId method from the class.
the size still remains 2. Why is it not 1? Does the in-variants get destroyed?
If you modify any of the properties used to compute hashCode and equals for an instance already in the HashSet, the HashSet implementation is not aware of that change.
Therefore it will keep the two instances, even though they are now equal to each other.
You shouldn't make such updates for instances that are members or HashSets (or keys in HashMaps). If you must make such changes, remove the instance from the Set before mutating it and re-add it later.

Override object equals [duplicate]

This question already has answers here:
Why is equals() not called while adding to HashSet and hashCode matches?
(5 answers)
Closed 6 years ago.
I have this method:
private static void searchChannelByName(String name, ArrayList<VeediChannel> channel,HashSet<VeediChannel> newChannelsList)
{
if(channel!=null) {
for (int i = 0; i < channel.size(); i++) {
if (channel.get(i).getName().toUpperCase().contains(name))
newChannelsList.add(channel.get(i));
}
}
}
I want to override to set the logic in which the set add is done (for preventing duplicates) so in VeediChannel class i am doing this:
#Override
public boolean equals(Object o)
{
Log.i(Utils.TAG,"In equals");
if(this.getName().equals(((VeediChannel) o).getName()))
return true;
else
return false;
}
So when the add method is called on the newChannelsList the equals is supposed to be called
but, when checking the logs the equals method dont get call at all
What seems to be the problem?
If you override equals without overriding hashCode, the add method of HashSet may look for the added element in the wrong bucket, and if there are no entries in that bucket, equals will never be called.
Even if you overridden both equals and hashCode, it's possible that equals won't be called when adding elements to the HashSet, if there are no duplicates and each element happens to be mapped to a different bucket.
Your hashCode implementation must be compatible with the equals implementation. For example:
#Override
public int hashCode ()
{
return getName().hashCode();
}
You are adding to a HashSet, which does not normally use equals unless there is a collision. It looks like for the set you are constructing, there are no collisions, which means that the default hashing algorithm is using its job.
However, you will want to override your hashCode method in addition to equals. The basic requirement is that two equal object must have the same hash value. A simple implementation that satisfies this condition is
#Override
public int hashCode()
{
Log.i(Utils.TAG,"In hashCode");
return this.getName().hashCode();
}
As mentioned in comment, you must override hashCode() as well.
Here's a good detailed answer on this theme: https://stackoverflow.com/a/27609/3941803

Not sure what Oracle means by having different hashcodes while objects are equal? [duplicate]

This question already has answers here:
What issues should be considered when overriding equals and hashCode in Java?
(11 answers)
Closed 8 years ago.
I do not get what Oracle means by followings: It seems to me the first and second ones are the same, the hashcode of two equal objects should always be the same! And for the last one does that mean, lets say in the following code change the value of prime in other classes?
1) 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.
2) 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.
3) It is not required that if two objects are unequal according to the
Object.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.
MyCode
public class Derived {
private int myVar;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + myVar;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Derived other = (Derived) obj;
if (myVar != other.myVar)
return false;
return true;
}
}
In order for an object to function correctly in hash tables, it's important for the hashCode() function to return consistent values. In particular 2 logically equal values must have the same hashCode(), otherwise you'll see flakiness.
The reason is the way hash tables typically work. A common implementation is a single array of pointers to "buckets". To find an object, hashCode() is called, then a modulus is taken to find an index in this array. Once we find the index, we look in the bucket for the objects, perhaps testing == and equals() until hitting a match.
Let's say an object 'foo' is in the table with hashCode() 1234. Now we search for an object claiming to be 'foo' but its hashCode() is different. Very likely we'll look in the wrong bucket, thus we'll fail to find a match even if both objects return a true equals(). Likewise the table assumes the hash code is stable (immutable).

Need explanation of this program in java [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm trying to understand, how the compareTo method is called in this program.
class Student implements Comparable {
String dept, name;
public Student(String dept, String name) {
this.dept = dept;
this.name = name;
}
public String getDepartment() {
return dept;
}
public String getName() {
return name;
}
public String toString() {
return "[dept=" + dept + ",name=" + name + "]";
}
public int compareTo(Object obj) {
Student emp = (Student) obj;
System.out.println("Compare to : " +dept.compareTo(emp.getDepartment()));
int deptComp = dept.compareTo(emp.getDepartment());
return ((deptComp == 0) ? name.compareTo(emp.getName()) : deptComp);
}
public boolean equals(Object obj) {
if (!(obj instanceof Student)) {
return false;
}
Student emp = (Student) obj;
boolean ii = dept.equals(emp.getDepartment()) && name.equals(emp.getName());
System.out.println("Boolean equal :" +ii);
return ii ;
}
public int hashCode() {
int i2 = 31 * dept.hashCode() + name.hashCode();
System.out.println("HashCode :" + i2);
return i2;
}
}
public class CompareClass {
public static void main(String args[]) {
Student st[] = { new Student("Finance", "A"),
new Student("Finance", "B"), new Student("Finance", "C"),
new Student("Engineering", "D"),
new Student("Engineering", "E"),
new Student("Engineering", "F"), new Student("Sales", "G"),
new Student("Sales", "H"), new Student("Support", "I"), };
Set set = new TreeSet(Arrays.asList(st));
System.out.println(Arrays.asList(st));
System.out.println(set);
}
}
Why is Arrays.asList(st) used?
What is use of equals() and hashcode()?
Why Arrays.asList(st) is used ?
Because the TreeSet constructor TreeSet(Collection c) accepts a Collection and not a String[] , hence you convert the String[] to a List which is a Collection using the method List asList(T... a). Note here , the array is same as varargs in this case.
What is use of equals() and hashcode() ?
Object class provides two methods hashcode() and equals() to represent the identity of an object.
You are using a TreeSet in your code . As per the documentation:
the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal.
Hence in your case , implementing Comparable and overriding compareTo() is enough .
Suggested Reading:
Overriding equals and hashCode in Java.
Hashset vs Treeset
What is the difference between compare() and compareTo()?
.equals() is used because you are comparing two Objects.
There is a very good explanation of the Comparable interface in the Oracle documentation: http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html
In this code, Arrays.asList(st) is used basically because the author thought it was simpler to instantiate an Array in Java and convert it to a List than it is to create an ArrayList and call .add for each item. It's really not critical to what is going on, though. Another thing that happens on that same line is where the magic is.
Set set = new TreeSet(Arrays.asList(st));
This creates a TreeSet from the list. It is worth taking a look at this post: What is the difference between Set and List? briefly. In a Set, all elements are unique, so when you create a Set from a List that contains duplicates the Set constructor will throw the extra items away. How does it determine what elements are duplicates? It uses the methods of the Comparable interface. Similarly, a List is sorted but a Set is not so the implementation can choose to store the items in the Set in whatever order is most efficient. In the case of a TreeSet it handily explains how it does it right at the top of the Oracle documentation:
Note that the ordering maintained by a set (whether or not an explicit
comparator is provided) must be consistent with equals if it is to
correctly implement the Set interface. (See Comparable or Comparator
for a precise definition of consistent with equals.) This is so
because the Set interface is defined in terms of the equals operation,
but a TreeSet instance performs all element comparisons using its
compareTo (or compare) method, so two elements that are deemed equal
by this method are, from the standpoint of the set, equal. The
behavior of a set is well-defined even if its ordering is inconsistent
with equals; it just fails to obey the general contract of the Set
interface.
Some of the Java API was built around arrays and some of it was built around collections. asList is basically an adapter that lets your array be accessed like a collection.
Some data structures and algorithms operate on what's called the "hash" of a piece of data. This is done largely for performance reasons. In most cases the hash is a single number representing a particular object. You can see how this might be useful for sorting a collection quickly or checking equivalence.
equals exists of course to test if two objects represent the same thing.
I m trying to understand ,how the compareTo method is called in this program.
Because what you use here is a TreeSet, which implements SortedSet, and for which uniqueness is calculated by comparing elements using their natural ordering, and not equality.
Classes implementing Comparable of themselves, or a superclass of themselves, can be compared to one another. For classes which do not, you can supply a Comparator instead.
When you add an element to a SortedSet, the set will first compare it to elements already present in the set, and only add it if no comparison gives 0. See below for a demonstration.
See also Collections.sort().
1.Why Arrays.asList(st) is used ?
because this is Java 1.4 code. In Java 5, you'd use Arrays.asList(s1, s2, etc) (ie, a varargs method).
2.What is use of equals() and hashcode() ?
In this case, none.
Sample program (with generics this time) illustrating the difference between a SortedSet and a HashSet, using BigDecimal:
final BigDecimal one = BigDecimal.ONE;
final BigDecimal oneDotZero = new BigDecimal("1.0");
one.equals(oneDotZero); // false
one.compareTo(oneDotZero); // 0
// HashSet: uses .equals() and .hashCode();
final Set<BigDecimal> hashset = new HashSet<>();
hashset.add(one); hashset.add(oneDotZero);
hashset.size(); // 2
// TreeSet: uses Comparable
final Set<BigDecimal> treeset = new TreeSet<>();
treeset.add(one); treeset.add(oneDotZero);
treeset.size(); // 1
.equals and .hashcode are methods inherited from the Object class in java by every class.
When creating your own class you would usually override these two default implementations because the default Object function generally does not lead to the desired behavior.
They are there for good measure really, but as it is they are not being used.

Creating a hashCode() Method - Java

I'm having some trouble writing a hashCode() method for a class I created. This class is meant to be used inside a TreeSet, and as such, it implements Comparable. The class has the following variables:
public class Node implements Comparable<Node> {
Matrix matrix;
int[] coordinates= new int[2];
Node father;
int depth;
int cost;
Here's the implementation of the compareTo() method. I want the TreeSet to organize these Node structures by their cost, therefore, compareTo() returns the result of a simple subtraction.
public int compareTo(Node nodeToCompare) {
return this.cost - nodeToCompare.cost;
}
I also implemented an equals() method.
public boolean equals(Object objectToCompare) {
if(objectToCompare== this) {return true;}
if(objectToCompare== null || objectToCompare.getClass()!= this.getClass()) {return false;}
Node objectNode= (Node) objectToCompare;
return this.father.equals(objectNode.father) &&
this.depth== objectNode.depth &&
this.cost== objectNode.cost &&
this.matrix.equals(objectNode.matrix) &&
Arrays.equals(this.coordinates, objectNode.coordinates);
}
Having said all of that, I have a few questions:
Since I implemented a new equals() method, should I implement a new hashCode() method?
How can I go about implementing a new hashCode method() with those variables? (Note that the variable matrix of the type Matrix has a hashCode() method implemented)
That's all!
Your compareTo method is not consistent with your equals method: your compareTo method says that two instances are equivalent if they have the same cost — such that a TreeSet can only ever contain at most one instance with a given cost — but your equals method says that they're only equivalent if they have the same cost and are the same in various other ways.
So, assuming that your equals method is correct:
you need to fix your compareTo method to be consistent with it.
you need to create a hashCode method that is consistent with it. I recommend using the same sort of logic as is used by java.util.List.hashCode(), which is a straightforward and effective way to assemble the hash-codes of component objects in a specific order; basically you would write something like: int hashCode = 1;
hashCode = 31 * hashCode + (father == null ? 0 : father.hashCode());
hashCode = 31 * hashCode + depth;
hashCode = 31 * hashCode + cost;
hashCode = 31 * hashCode + matrix.hashCode();
hashCode = 31 * hashCode + java.util.Arrays.hashCode(coordinates);
return hashCode;
Intellij IDEA can do this as a ' right-click' feature. Just seeing it done correctly will teach you alot.
And you should override both in any case.
The contract for the hashCode method states that if two objects are equal, then calling hashCode() should give you the same integer result. The opposite does not have to be true, i.e. if two hashCodes are the same the objects don't have to equal each other.
Looking at your equals method (which needs variable translation btw), you can add the hashCodes of all the internal member variables that need to be equals for your equals method to give true. e.g.
public int hashCode() {
return this.matrix.hashCode() +
this.coordinates[0] +
this.coordinates[1] +
this.father.hashCode() +
this.depth + this.cost;
}
The above assumes that matrix and father are never nulls, you need to make sure that you check for nulls if that's not the case.
If you feel more adventurous you can multiply a few of the above with a prime to ensure you don't get hashCode collisions for different data (this will help improve performance if you are using your class in hashTables and hashMaps). If you need to cater for nulls, the above method can be written a bit better like this:
public int hashCode() {
return ((this.matrix == null) ? 0 : this.matrix.hashCode()) +
17 * this.coordinates[0] +
this.coordinates[1] +
((this.father == null) ? 0 : this.father.hashCode()) +
31 * this.depth + 19 * this.cost;
}
If your collection is small you can return constant from hashCode method. It use for quick finding. hashCodes is like the boxes, which keep elements. Rules are:
Equal elements must be in same box (have same hashCode) - surely;
Not equal elements can be either in same or in different boxes.
Then you return constant, you obey these 2 rules, but it can significantly decrease perfomance on not small lists (because JVM will look for in all elements, and not in elements in the same box only). But return constant is the bad approach.
PS: Sorry for my writing. English is not my native language.
PPS: usualy you have to implement hashCode method in the same way as equals (use same elements)

Categories