Dilemma with hashCode() - Java - java

I have the following code,
Object testA = new Object();
Object testB = testA;
System.out.println("A:"+testA.hashCode())
System.out.println("B:"+testB.hashCode())
Per the above, I get the same hashcode for the two objects. I understand that testB is assigned testA and so it could have the same hashcode, however there should be a way to uniquely identify the difference in both these objects right?
Please let me know if there is something obvious that am missing!

however there should be a way to uniquely identify the difference in both these objects right?
There is no difference, since there are no two objects. There is just one object referred by two variables.
In theory, two different objects may have the same hashCode. You can tell them apart by using equals or by using ==. If you don't override equals, it behaves as == by default.

The hashCode function has to be compatible with the equals method in the sense that hashCode has to return the same value for 2 objects that are equal. In this case, they are not only "equal" (according to the equals method), but even the same object (which implies that they are equal).
Besides, independently of what the specification demands, it would impossible for the 2 calls to hashCode to return different values because both variables are actually referencing the same object. There is no way to distinguish testA and testB (apart from the variable name, of course).

You create a new object testA but then assign testB to testA, which assigns the same memory space for both of the objects. This is why its returning the same HashCode.

Related

Why does the equals() method return false when the two objects are identical?

public class Test {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
System.out.print((o1 == o2) + " " + (o1.equals(o2)));
}
}
I read this in a different answer:
The == operator tests whether two variables have the same references (aka pointer to a memory address).
Whereas the equals() method tests whether two variables refer to objects that have the same state (values).
Here, since o1 and o2 reference two different objects, I get why == returns false.
But both the objects are created using the default constructor of the Object class, and therefore have same values. Why does the equals() method return false?
The implementation of equals() supplied by java.lang.Object is defined to return false, unless the references refer to the same object, in which case it returns true.
This is by design (the method mimics the behaviour of ==) and encourages programmers to implement their own version of equals(), if appropriate, for their class. For example, see java.lang.String#equals which compares the contents if another String is passed as an argument.
You have to write your own equals method that overrides the equals method of class Object because that method returns true if this object is the same as the object in the argument and false otherwise.
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). (for more information, read Javadoc)
All Java objects inherit from the Object class. The methods of Object, therefore, are available to all Java objects. One of these methods is equals().
The implementation for equals() in class Object, by default, is identical to the == operator.
If a programmer wishes to use equals() to test objects for value equality, he must override equals() and provide his own implementation (that should comply with the general contract for equals(); refer to the Javadoc).

Why in the first print it says different while a and b are indentical?

public class SomeClass {
public static void main(String[] args){
int[] a={1,2,3};
int[] b={1,2,3};
int[] c=a;
String s="Neanderthal";
String s2="Neanderthal";
String s3=s;
System.out.println((a.equals(b))?"Same":"Different");
System.out.println((a.equals(c))?"Same":"Different");
System.out.println((s.equals(s2))?"Same":"Different");
System.out.println((s.equals(s3))?"Same":"Different");
}
}
The 1st system.out.print returns the value different and i cannot see a reason for this, and all the others are the same. Please help me understand this
Unlike Strings which are compared for equality character-by-character *, Java arrays are compared only for reference equality. You need to use Array.equals or Array.deepEquals to do the comparison:
System.out.println(Arrays.equals(a, b) ? "Same" : "Different");
* Since your code uses string literals, s and s2 would refer to the same object instance. However, this is not critical to understanding the issue at hand, because interning is not applicable to arrays.
When you say
int[] a={1,2,3};
int[] b={1,2,3};
a is pointing to an array, b is pointing to another array. Both the arrays are not same in the memory. That is, they both are pointing to different memory locations.Like :
a------------->|mem_loc_1|
b------------->|mem_loc_2|
Hence, equals() method tells you that both references are NOT pointing to same object.
Whereas when you say c= a;, the situation is :
a -------------> |mem_loc_1| <---------------- c
Hence equals() tells you that YES, a and c references reference to same objects.
Conclusion, when you say c = a; there are TWO references, but a single object in the memory.
P.S. Sorry for the bad graphical representation,just wanted to simplify things.
because it doesn't do deep equals and does just shallow equals, Use Arrays.deepEquals(); to get expected output
Before understanding above concept you need to note few things :
equals() method is defined in Object class, and any class can
override it.
By default equals() method use memory address of objects to compare them.
So, if you do not overriding it then it will call Object's method.
String class has overridden version of equals() method.
Now come on your program :
In first print statement you are comparing two different object which has not overridden equals() method, so it use Object's method and obviously it check memory address which is different.
In second print statement two reference variable refer same object so its address are same and equals() method return true.
In other print statements for string, which has overridden equals() method, so it will check only actual (here string value) content of object it doesn't matter two String reference variable referring same object or different.

questions regarding hashcode

I have some doubts regarding equals and hashcode. What I have understood previously is, we need to override the hashcode() and equals() method in the object class if that class is supposed to add to the collection class or Map class. Please see the below example. I did not override the hashcode and equals method. Still I get the desired result what I want. One thing i understood that, If I want to compare two object we need to override the equals method. But in this example I am not comparing two objects, rather I am adding objects to collection or Map without overriding the hashcode and equals. Could anyone explain why do we need to override the hashcode and when?
package equalshashcode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EqualsAndHashCode {
public static void main(String[] args) {
Student student1 = new Student("A");
Student student2 = new Student("B");
List<Student> studentList = new ArrayList<Student>();
Map<Integer,Student> studentMap = new HashMap<Integer,Student>();
studentMap.put(1, student1);
studentMap.put(2, student2);
studentList.add(student1);
studentList.add(student2);
System.out.println("Student HashMap:: "+studentMap.get(1));
System.out.println("Before removing::"+studentList);
System.out.println(studentList.remove(student1));//true success
System.out.println("After removing::"+studentList);
}
}
class Student{
String name;
public Student(String pName){
this.name = pName ;
}
public String getName(){
return this.name ;
}
}
You don't always need to implement equals() and hashCode() to add elements into a collection.
For a List (such as you studentList, which is an ArrayList instance) it doesn't matter for most actions.
The only places where you need equals() and hashCode() is where "equality" of objects is relevant. And even in those places the default implementation might even be sufficient.
Equality matters in several cases, for example:
A Set can't contain two objects that are equal to each other
The key of a Map must have a correct equals() implementation to be retrievable (and based on the concrete Map implementation, that might imply that hashCode() has to be correctly implemented as well).
Some methods on a "normal" List also need equality. For example contains(), indexOf() and remove(Object) need correctly implemented equals()/hashCode()
Custom equals and hashCode methods are generally used for determining actual equality. If you rely on the default equals method, this will look for the same instance in memory. For example customObj1.equals(customObj2) will return false if there's no custom equals method and the two objects are separate (but otherwise equal) instances. The idea of a custom equals method is to make that same example return true if they are actually equal. A Map will then be able to use this to match the key object passed in a get(key) request to find the value without needing to have the correct instance of the key (a HashMap actually uses hashCode to do this).
The most obvious example of this being useful is for Strings, so that you can do myMap.get("key") and get the correct value, even if your key instance isn't the same as the one stored in the Map (String implements equals and hashCode for you). In general I would recommend using these Java built-in equals and hashCode methods to construct your own. For example if your object has a natural ID, such as say userName, your equals can use the String version of this to complete your own equals (you can obviously compare multiple fields):
public boolean equals(Object o) {
if (o instanceof MyObj) {
return userName.equals(((MyObj) o).userName));
}
return false;
}
As such, if you'll only be working with a single Thread, or otherwise limited variables, you'll likely never need to implement these methods, but there are certainly times when it pays off to know them.
Collection classes will work perfectly well with objects that have the default equals/hashCode implementations - there is no need to add your own for this reason.
Custom equals/hashCode methods are easy to get wrong, and unless you have a good reason to roll your own you should just stick with the ones that you get for free with java.lang.Object.
The most common reason for creating your own version of these methods is if you want to treat two separate instances of the same class as being equal. For example, if you have an Account class and you want two instances of Account which have the same accountNumber property to be regarded as equal, because they represent the same real-world account. In this case you would base your equals method on the value of accountNumber alone, and since you now have a custom equals method you need to provide a suitable implementation of hashCode as well, in order to fulfil the equals/hashCode contract.

Google Guava / Equivalence / different equals() and hashCode() method implementations

I want to be able to switch between two equals-Implementations, but I'm not sure if the Equivalence class of Google Guava maybe provides this functionality. Let's say I have two equals methods equalsContent() and equalsKeys() or something like that I somehow want to delegate the equals method to one of the two private methods (and the same for the two hashCode methods).
Well, I'm somehow not sure what the usage of the Equivalence abstract class and the Equivalences class (static methods) is.
Besides, how would you implement the desired properties described above? I could use another method which simply sets a flag or an enum to the value and implement the two equals and hash methods inside an enum with two abstract methods (equals(), hashCode()) and simply call enum.equals() or enum.hashCode() in the equals() and hashCode() method. What do you think?
I think the enum approach would make sense from an object-oriented point of view, but it's dangerous. It could break the equals() and hashCode() contract (reflexivity, symmetry, and transitivity). For example, inserting an instance that uses the first equivalence strategy and an instance that uses the second equivalence strategy in the same Set would cause problems.
If you want different equivalence relationships, you should keep those out of your class. Equivalence lets you do just that: you extract the equivalence logic (equals() / hashCode()) by implementing Equivalence and overriding the doHash() and doEquivalent() methods.
Then, when you want to use a Collection based on one equivalence or the other, you use Equivalence.wrap(). For example, you could emulate an IdentityHashSet by doing:
Set<Equivalence.Wrapper<String>> identityHashSet = Sets.newHashSet();
String a1 = "a";
String a2 = new String("a");
String b = "b";
identityHashSet.add(Equivalences.identity().wrap(a1));
identityHashSet.add(Equivalences.identity().wrap(a2));
identityHashSet.add(Equivalences.identity().wrap(a3));
// identityHashSet contains "a", "a", and "b"
// a standard HashSet would only contain "a" and "b"
// while a1 and a2 are equal according to String.equals(), they are different instances.
Of course, you could use ForwardingSet to automate the wrapping / unwrapping of your elements.
There is more info in this Guava issue.

Java String hashCode of null string

Only interesting, why method hashCode() in java.lang.String is not static?
And in case of null return e.g. -1 ?
Because frequently need do somethihg like:
String s;
.............
if (s==null) {
return 0;}
else {
return s.hashCode();
}
Thanks.
As others have noted hashCode is a method on Object and is non-static because it inherently relies (i.e. belongs to) an object/instance.
Note that Java 7 introduced the Objects class, which has the hashCode(Object) method, which does exactly what you want: return o.hashCode() if o is non-null or 0 otherwise.
This class also has other methods that deal with possibly-null values, such as equals(Object, Object), toString(Object) and a few others.
because if it was static "1".hashCode() and "2".hashCode() would have returned the same value, which is obviously wrong.
It is specific per instance, and influenced by it, therefore it cannot be static.
Because the hash code of a String is a property of that String.
With the same train of thought you could make every method static.
hashCode is used to get the hashCode of an object, in order to know in which bucket of a HashMap this object must be placed. It thus has to be an instance method of the object, and it must be called polymorphically.
null can be used as a key in a HashMap, but it's treated as a special case.
You seem to be using hashCode for a different purpose, so you have to handle is in a specific way.
Its returning hashCode of an Object not an class.

Categories