Behavior of default `equals` changes when member/setter is added? - java

I have a question about the Java "equals" method.
I created a class called Person:
public class Person {
}
And I am comparing two references to Person like this.
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.equals(p2)); //returns false
If I add any instance variable and setter method to set the instance variable, then the "equals" method returns true.
Can anybody explain this behavior?

If you do not override Object.equals(Object) then the default implementation uses the objects identity for comparison. (i.e. equals only returns true if the objects are the same object in memory).
Relevant JavaDoc: Object.equals
Excerpt:
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).
Object a = new Object();
Object b = new Object();
System.out.println(a.equals(b)); // Prints 'false'
b = a;
System.out.println(a.equals(b)); // Prints 'true'
As I mentioned in one of my comments the additions of methods or fields should not affect the default implementation of equals method, something else must be going on.

p1 and p2 are two different references, that's why. It will return false unless you have your own equals method. It doesn't matter if you have instance variable or not.

Related

equals() method and object comparing [duplicate]

This question already has answers here:
What is the difference between == and equals() in Java?
(26 answers)
Closed 9 years ago.
The equals method compares whether two object values are equal or not. My question is how it compares the two objects? How can it tell the two objects are equal or not? I want to know based on what it compares the two objects. I am not including the hashCode method.
The default implementation, the one of the class java.lang.Object, simply tests the references are to the same object :
150 public boolean equals(Object obj) {
151 return (this == obj);
152 }
The reference equality operator is described like this in the Java Specification :
At run time, the result of == is true if the operand values are both
null or both refer to the same object or array; otherwise, the result
is false.
This default behavior isn't usually semantically satisfying. For example you can't test equality of big Integer instances using == :
Integer a = new Integer(1000);
Integer b = new Integer(1000);
System.out.println(a==b); // prints false
That's why the method is overridden :
722 public boolean equals(Object obj) {
723 if (obj instanceof Integer) {
724 return value == ((Integer)obj).intValue();
725 }
726 return false;
727 }
which enables this :
System.out.println(a.equals(b)); // prints true
Classes overriding the default behavior should test for semantic equality, based on the equality of identifying fields (usually all of them).
As you seem to know, you should override the hashCode method accordingly.
Consider following example,
public class Employee {
String name;
String passportNumber;
String socialSecurityNumber;
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee();
boolean isEqual = e1.equals(e2); // 1
System.out.println(isEqual);
}
}
In the code at comment //1 it calls inherited equals method from Object class which is simply comparing references of e1 and e2. So it will always give false for each object created by using new keyword.
Following is the method excerpt from Object
public boolean equals(Object obj) {
return (this == obj);
}
For comparing equality check JLS has given equals method to override in our class. It is not final method. JLS doesn't know on what basis programmar wants to make two objects equal. So they gave non-final method to override.
hashcode does not play role to check object's equality. hashcode checks/finds the Bucket where object is available. we use hashcode in hashing technique which is used by some classes like HashMap..
If two object's hashcode are equals that doesn't means two objects are equal.
For two objects, if equals method returns true then hashcode must be same.
You will have to override equals method to decide on which basis you want object e1 and e2 in above code is equal. Is it on the basis of passportNumber or socialSecurityNumber or the combination of passportNumber+socialSecurityNumber?
I want to know based on what it compares the two objects.
Answer is, by default with the help of inherited Object class's equals method it compares two object's reference equality by using == symbol. Code is given above.
logically, equals does not compare objects (however you can do anything with it), it compares values. for object comparison there is '==' operator

Java Reflection Class

Why is second SOP showing output as true here, I was hoping it would display false like first SOP ?
public class reflect1 {
public static void main(String[] args) {
Reflect1A obj1 = new Reflect1A();
Reflect1A obj2 = new Reflect1A();
System.out.println(obj1 == obj2);
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
System.out.println(c1 == c2);
}
}
class Reflect1A {
}
From the Java Language Specification
The method getClass returns the Class object that represents the class of the object.
A Class object exists for each reference type. It can be used, for
example, to discover the fully qualified name of a class, its members,
its immediate superclass, and any interfaces that it implements.
Since both your objects are of type Reflect1A, they both return the same Class object.
You would get the same object by doing
Class<?> clazz = Class.forName("com.example.Reflect1A")
System.out.println(c1 == clazz); // true
(though this is not necessarily required by all classloaders.)
The values of obj1 and obj2 refer to different objects - when you use == in Java and both operands are references, the result is to compare whether those references refer to the exact same object. In this case you've got two different objects, so the references are not the same.
However, they're both of the same class, so that's why c1 == c2 is true.
The first line prints false because it is a different instance of the same class.
The second line prints true because it is the same class type. There is a obscure gotcha here to be aware of, if you're in a multiple classloader environment, e.g. an application server like JBoss, or OSGI etc, it is possible for two class instances to not be equal
An object is equal (==) only to itself. So clearly both getClass() statements are returning the same Class object
Because obj1 and obj2 are different instances (first check is false) of the same type (class - second check is true).
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass%28%29
why did you expect to return false?
The operator == compares the references in which the objects are created by default
Obj1 and Obj2 are of same type class Reflect1. For these objects are equal only when compared like this obj1.equal(obj2).
While the class type of obj1 and obj2 are the same == operation will be true.

what does obj1 == obj2 actually compare

I am studying Overriding hashCode() and equals(Object obj) methods of Object class.
body of equals(Object obj) method in Object class is :
public boolean equals(Object obj) {
return (this == obj);
}
and hashCode() is native :
public native int hashCode();
I have a class Test with overrided equals(Object obj) and hashCoe() :
public class Test {
public static void main(String[] args){
Test t1 = new Test();
Test t2 = new Test();
System.out.println("t1 toString() : " + t1.toString());
System.out.println("t1, Hex value of hashcode : " + Integer.toHexString(t1.hashCode()));
System.out.println("t2 toString() : " + t2.toString());
System.out.println("t2, Hex value of hashcode : " + Integer.toHexString(t2.hashCode()));
System.out.println(t1.equals(t2));
}
#Override
public int hashCode() {
return 999; //hard coded value is just for testing
}
#Override
public boolean equals(Object obj) {
return (this == obj);
}
}
Output of my Code is :
t1 toString() : demo.Test#3e7
t1, Hex value of hashcode : 3e7
t2 toString() : demo.Test#3e7
t2, Hex value of hashcode : 3e7
false //why it is false
why equals(Object obj) returns false in this case if both objects toString() returns the same reference ID (hashcode) [I am not sure if it compares hashcode or not].
What does == operator actually compare in case of objects?
in this answer, answerer said that == that is, it returns true if and only if both variables refer to the same object, if their references are one and the same.
How does it know that the variables refer to the same object???
How does it know that the variables refer to the same object?
Because the values of the variables are the same references. (Your variables are t1 and t2. The values of those variables are references. Those references are used as a way of navigating to objects, basically.)
Suppose you and I both have pieces of paper with a house's street address on (that's my usual analogy for "variables with references"). How do we check whether they refer to the same house? We see whether the address is the same.
There are some potential twists here, as in some cases the form of the reference may not be the same between two expressions, but that's the basic idea.
(Note that just because I've used "address" in the analogy, that doesn't mean a Java reference is always a memory address. It's "a way of navigating to an object", that's all. It may or may not just be an address.)
From the JVM specification section 2.2:
The Java Virtual Machine contains explicit support for objects. An object is either a dynamically allocated class instance or an array. A reference to an object is considered to have Java Virtual Machine type reference. Values of type reference can be thought of as pointers to objects. More than one reference to an object may exist. Objects are always operated on, passed, and tested via values of type reference.
== will check if both references are the same. You have 2 different objects, no matter they are equivalent, they point to different memory blocks.
The only exception to this rule is String, in special conditions(i.e. invoking .intern() method), but that's really a special case, related to String pool.
If you compare with == equals, the instances of the Object needs to be the same (pointer to the same reference, "same id" in the JVM). The hashcode of the object is'nt checked.
This is why it is a good practice to compare with equals(..) in Java.
Here some code:
Test o1 = new Test();
Test o2 = new Test();
//You can check the ids with System#identityHashCode(Object):
System.out.println(System.identityHashCode(o1));
System.out.println(System.identityHashCode(o2));
o1 == o1 // will be true
o1 == o2 // will be false
o1.equals(o2) //depends on how you have implemented equals() and hashCode() in the Test Object.
The contract between hashCode and Equals is:
objects which are .equals() must have the same .hashCode()
The reverse statement does not need to be true.
In your example, it is exacly the case: you return 999 in .hashCode() and you compare the jvm ids in .equals().
== checks to see if the two objects refer to the same place in memory. In other words, it checks to see if the 2 object names are basically references to the same memory location
EX1:
String obj1 = new String("xyz");
String obj2 = new String("xyz");
obj1==obj2; //False
EX2
String obj1 = new String("xyz");
String obj2 = obj1;
obj1==obj2; //True

Questions with updating objects in java

If I have an instance of an object, and within that object is a variable that holds the data of another object. If I ever update the second object will the copy of that object be updated as well or do I need to simultaneously update all copies of said object.
For example:
public class Object()
{
int x = xValue;
Object linked = saidObject;
}
public class doStuff()
{
saidObject.x++;
if(linked.equals(saidObject))
return true;
}
will this code (not compilable obviously just fill in blanks) return true?
if(linked.equals(saidObject)) will return true as the two variables do point to the same object.
In Java all variables and fields are references to an actual Object that lives somewhere in memory.
When you assign one variable to another, it's like copying the address of the object so that they both point to the same object in memory.
e.g.
Object a = new Object(); // this actually creates the Object in memory
Object b = a; // this copies the reference to Object from a to b
// At this point, a and b point to exactly the same object in memory. Therefore ...
a.equals(b); // returns true.
In fact a == b returns true too, which is a better way of comparing for this case as == compares if two variables point to the same object (they do), whereas equals() often compares by value, which is unnecessary here.
It doesn't matter if b is actually a field within a (e.g. class Obj { Obj b; }; Obj a = new Obj(); a.b = a;) and it points to the same type of object, the principle is the same: a = b means they point to same object, nothing new is created.
By doing:
Object linked = saidObject;
you are not copying the object, just creating another pointer to it, it means you have two different pointers that point to the same object.
copying or cloning an object can be useful in some cases but its not the usual case.
An object instance is itself and is distinct from every other instance.
That is, mutating an object (by reassigning a field) someplace modifies it everywhere .. as, well, it is what it is. Likewise, mutating a different object .. is, well, changing a different object.

How the equals() method works

I am digging into the basics of Java. I infer from this article, that the Java 'equals' method means, if two objects are equal then they must have the same hashCode().
Here's my example.
public class Equals {
/**
* #param args
*/
public static void main(String[] args) {
String a = new String("a");
String b = new String("a");
System.out.println("a.hashCode() "+a.hashCode());
System.out.println("b.hashCode() "+b.hashCode());
System.out.println(a == b);
System.out.println(a.equals(b));
}
}
Output:
a.hashCode() 97
b.hashCode() 97
false
true
The actual Java language 'equals' method:
public boolean equals(Object obj) {
return (this == obj);
}
In my above example, a.equals(b) has returned true, meaning the condition 'a==b' is satisfied. But then why is 'a==b' returning false in that example?
Aren't hashCode and address one and same? Also, is 'hashCode' compared when we say 'a==b' or something else?
The String class has overridden the equals() method. Please follow the String equals() documentation.
a.equals(b) has returned true, meaning the condition a==b is satisfied
This is the default implementation of equals() in the Object class, and the String class has overridden the default implementation. It returns true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
Aren't hashCode and address one and same?
Not necessarily. For further reading on hashCode().
The == operator in Java compares object references to see if they refer to the same object. Because your variables a and b refer to different objects, they are not equal according to ==.
And the hashCode method doesn't return the address in String, because that class has overridden hashCode.
Additionally, the equals method has been implemented in String to compare the contents of the strings; that's why a.equals(b) returns true here.
No, Hashcode and address aren't the same.
Because a==b is not comparing hashcodes.
Yes, something else is compared when we say a==b.
(that's not addresses either, really, but it's close enough).
Also, just because "equal objects have equal hashcodes" does not mean "equal hashcodes means equal objects".
a.equals(b) is different from a==b.
a.equals(b) checks if two objects are equals based on equals() implementation.
a==b checks if two objects have same reference.
If a==b is true then a.equals(b) must be true because they are referencing to the same object but not vice-versa.
String class overrides the default implementation of the equals() method of the Object class. The equals method code that you have provided is not from String class but from the Object class, which is overridden be the String class implementation which checks if the contents of the two objects are same or not.
Hashcode for an object is meant to be overridden.
For String class the formula used is as follows:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
I encourage you to search why 31 has been used as a multiplier and not some other number.
A general thumb rule for overriding hash code is that for different objects hash code should be different as far as possible.
To achieve this it is advisable that you take into account every significant field of an object while calculating the hash value.
Note: Just an unrelated food for thought (source : Effective Java):
Consider the following implementation of hashcode
int hashcode(){
return 10;
}
This is a valid implementation but it is also the worst possible one. Read about why.
A and B are two separate objects that generate the same hash code because of String's implementation of hashCode(). == just checks to see if the left and right sides share the same reference. It does not call an Object's equals() method.
So, no, hashes and object references are not the same thing.
public class TestEquals {
/**
* #param args
*/
public static void main(String[] args) {
String a = new String("a");
String b = new String("a");
System.out.println("a.hashCode() " + a.hashCode());
System.out.println("b.hashCode() " + b.hashCode());
// Checks the reference which is something like the
// address & address is different from hash code which can be overriden
System.out.println(a == b);
// It returns true if and only if the argument is not null
// and is a String object that represents the same sequence
// of characters as this object. (String Implementation of equals)
System.out.println(a.equals(b));
}
}
Output:
a.hashCode() 97
b.hashCode() 97
false
true

Categories