How is the == operator implemented in Java? - java

Specifically, in the case of object reference equality, what does the == operator do?
Does the comparison return true if the references evaluate to the same object address at the time of comparison? Or does it utilize the hashCode value of the two references to determine if the objects are the same?
To be very specific here, I would like to know what data structures managed by the JVM are referenced by the == operation for reference comparison. Does == rely on the OOP to perform reference comparison?
Unfortunately for me, the JLS does not define how the == operator must work. The Java API docs do not mention what == is supposed to do (they're for classes, right?)
PS: I was a bit intrigued by this question on hashcode uniqueness, and would prefer to know how the Sun JVM (or OpenJDK) implements the == operator.

The == operator just compares the references.
References in the JVM are just a standard object pointer. This works out to a single 32bit or 64bit integer value (depending on platform).
When you compare two object references, you're really just comparing two 32bit or 64bit integers, and if they're the same, you'll equate to equal. The integer values are a location in memory.

Because a reference is just a number, a reference comparison comes down to just comparing two numbers. No hash is needed.

The == operator compares object references to see if they are identical, i.e. they refer to the same object in memory.
The equals() method compares object references to see if they are equivalent, though not necessarily identical. The default implementation of equals() uses the == operator, but it often makes sense to override this behavior. For example, you might want two BankAccount references to be considered equivalent if they have the same account number, even if they are completely different objects.

The == operator returns true if the objects are the same object. There is not access to hashCode() or equals() here.
Try this to confirm:
public class Test {
static void testEqualEqual(Integer I0, Integer I1, boolean IsEquals) {
if(!(IsEquals == (I0 == I1)))
throw new AssertionError();
}
static void testEqual(Integer I0, Integer I1, boolean IsEquals) {
if(!(IsEquals == (I0.equals(I1))))
throw new AssertionError();
}
static void testHash(Integer I0, Integer I1, boolean IsEquals) {
if(!(IsEquals == (I0.hashCode() == I1.hashCode())))
throw new AssertionError();
}
public static void main(String ... args) {
testEqualEqual( 1, 1, true);
testEqualEqual(2000, 2000, false);
testEqual( 1, 1, true);
testEqual(2000, 2000, true);
testHash( 1, 1, true);
testHash(2000, 2000, true);
System.out.println("Done");
}
}
To understand this, you should know first that the number number 255 will be cached when autoboxed. This means that Integer of 1 is always the same object but Integer of 2000 will always be different object.
This experiment shows that '==' return true when the objects are the same. In case of '1' they are the same number and it returns true. But in case of '2000' autoboxed to be different objects so it returns false.
The experiment also shows that '==' does not use equals() or hashCode().
Hope this helps.

Related

default implementation of hashcode returns different values for objects constructed the same way

Here I am writing one sample code:
public class Test {
private int i;
private int j;
public Test() {
// TODO Auto-generated constructor stub
}
public Test(int i, int j)
{
this.i=i;
this.j=j;
}
}
now I am creating two objects as bellow:
Test t1= new Test(4,5);
Test t2 = new Test(4,5);
But when i am printing t1.hashcode() and t2.hashcode() they are giving different values.
But as per java's general contact they should return same value.
In fact, when i am doing same thing with String or Integer they are returning same hashcode(). Can anyone please explain why hashcode is different for t1 and t2 object?
But as per java's general contact they should return same value.
Java's equals-hashCode contract requires that if two objects are equal by Object.equals, they must have the same hashcode from Object.hashCode. But the default implementation of Object.equals is reference equality, and therefore two instances are the same if and only if they are the same instance.
Therefore, in particular, your two instances t1 and t2 are in fact not equal because you have not overridden Object.equals. They are not equal as references, and therefore not equal per Object.equals, and therefore it is acceptable for hashCode to possibly return different values. In fact, the contract explicitly says the following:
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.
Thus, we do not have a violation of the equals-hashCode contract here.
So, for your objects, if you want different instances to be equal per a logical definition of equality, you need to override Object.equals:
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
if (this == obj) {
return true;
}
if (!(obj instanceof Test)) {
return false;
}
Test other = (Test)obj;
return this.i == other.i && this.j == other.j;
}
And the equals-hashCode contract requires that you override Object.hashCode too or you'll run into some nasty bugs:
#Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + this.i;
hash = 31 * hash + this.j;
return hash;
}
What does the contract say:
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.
Let's see if we have satisfied this requirement here. If x and y are instances of Test and satisfy x.equals(y) is true, we have that x.i == y.i and x.j == y.j. Then, clearly, if we invoke x.hashCode() and y.hashCode() we have the invariant that at each line of execution in Test.hashCode we will have hash holding the same value. Clearly this is true on the first line since hash will be 17 in both cases. It will hold on the second line since this.i will return the same value whether this == x or this == y because x.i equals y.i. Finally, on the penultimate line, we will still have hash being equal across both invocations because x.j equals y.j is true as well.
Note that there is one last piece of the contract that we haven't discussed yet. This is the requirement that hashCode return a consistent value during a single execution of a Java application:
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.
The necessity of this is obvious. If you change the return value from hashCode during a single execution of the same application, you could lose your objects in hashtable-like data structures that use hashCode to keep track of objects. In particular, this is why mutating objects that are keys in hashtable-like data structures is pure evil; don't do it. I would go so far as to argue that they should be immutable objects.
In fact, when i am doing same thing with String or Integer they are returning same hashcode().
They've both overridden Object.equals and Object.hashCode.
You have not overridden the equals method in your class so the default one will be used that belongs to Object class.
Object class methods simply checks for the references whether they are referring to the same object or not.
Test t1 = new Test(4,5);
Test t2 = new Test(4,5);
are two different objects, if you don't override the equals method here, they will be equal if and only if you do
Test t2 = t1;
As you are creating two different objects here, hashcode which are NOT equal because they don't refer to the same object, hashcodes must be differnt
Remember
If two objects are equal, then their hashcode MUST be equal
But if hashcodes are equal, then its not necessary that objects should be equal
This is because of the default implementation of equals and hashCode in Java.
The JVM has no way of knowing how you decide that two objects are the same. What it does is use memory references. So, by default, the equals and hashCode methods compare memory references; i.e. two different objects are never .equals.
If you want to override this behaviour (and it is recommended you do so if you wish to use Collections for example) then all you need to do is implement your own equals and hashCode methods.
The problem is that t1 and t2 are not the same object they are different object. All objects created with new are different objects. And the default hashCode() implementation usually returns different hash codes for different objects. See Object.hashCode API.

Comparing two objects in Java

I have two different objects of same entity “Community”
And two objects(community and com) have same values
Communty.java have following variables:
private Integer communityId;
private String communityName;
private String description;
// many to many relationship
private Set<Faculty> faculties = new HashSet<Faculty>();
private Set<User> users = new HashSet<User>();
and I used equal method as:
#Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj==null)
return false;
if(obj==this)
return true;
if(!(obj instanceof Community)) return false;
Community community = (Community)obj;
return community.getCommunityId() == this.getCommunityId();
}
When I checked community==com , it returns false .. why? What mistake I have done? Both the objects are retrieved from the database!
== compares links to the objects.
You should explicitly call community.equals(com). Also take care of the null checks.
Because you're comparing objects (the IDs) using == rather than equals(). == tests if both variables reference the same object. equals() tests if the two variables reference two functionally equal integers (i.e. with the same int value).
It's almost always a bug to compare objects using ==, except for enums.
== compares the two references which may be pointing to two different locations irrespective of the object content.
You should use community.equals(com) to check for equality'
Also, your equals method contains the following segment :
community.getCommunityId() == this.getCommunityId()
as communityId is an Integer object, the == operator may give negative result for integer values which are not in the range [-127, 128] due to interning, thats a separate concept, you can check it later.
You need to use equals() there as well or compare the .intValue()
return community.getCommunityId().equals(this.getCommunityId())
Because, they don't refer same object. == used to check, whether both referring same object.
== for object refer to same.
equals content equivalency.
try this
return community.getCommunityId().equals(this.getCommunityId());
The problem of your equals method is that you are using == operator for Objects. And here the CommunityId must be the same object in order to return true:
return community.getCommunityId() == this.getCommunityId();
It should be
return community.getCommunityId().equals(this.getCommunityId());
When I checked community==com , it returns false .. why
This means; are these two references exactly the same. i.e. to the same object. What you intended was
boolean equal = community.equals(com);
BTW Your if (obj == null) check is redundant.
== operator in Java compares the memory address of the two objects,in your case comm and community must be two different objects stored at two different memory addresses
You are comparing two distinct objects communityId's.
is it necessary to declare communityId as Integer? because Integer is an object.
Why don't you simply declare communityId with a primitive type int;
int communityId should work.

Java integers Return Strange Result While Compare Two Integers?

Integer i1= new Integer(9);
Integer i2= new Integer(9);
if(i1==i2){
System.out.println("true");
}else{
System.out.println("false");
}
int i3=9;
int i4=9;
if(i3==i4){
System.out.println("true");
}else{
System.out.println("false");
}
if(i3==i2){
System.out.println("true");
}else{
System.out.println("false");
}
In Above Code First if-else print false, Why ?.But when second Return true and also third have true.I think wrapper classes(Like double,boolean,char)cant compare True ?
First if-else print false. Why?
== checks if the two references are referring to the same object, in this case they are not so the == check is false. You need to use Integer.equals(), not ==:
if (i1.equals(i2){
System.out.println("true");
}else{
System.out.println("false");
}
Second return true
== is correct to use for primitives: int is a primitive.
third have true
As pointed out by JB Nizet i2 is unboxed to an int which makes the if condition a check between two int primitives.
When == is used to compare references to objects, it returns true only if both references point to the same object.
In the first case, you have two different objects.
In the second case, you're not comparing objects, but primitive types.
In the third case, the Integer object is unboxed to its primitive int value to be compared with the primitive value, so two primitive values are compared.
You should never use == to compare objects, except for enums. Always use .equals().
Whenever you use "==", you are doing a object reference check. That means, the first check will fail since they are 2 different objects.
In the second case, its straight forward.
In the third case, the compiler autoboxes "i2". So, the comparison will work fine.
Remember you are not comparing 2 primitives but 2 Objects.. so Use .equals() method..
The variables i1 and i2 refer to Objects, not primitive types. Using the == operator on objects in Java checks that the references are equal, if you want to compare them you should use the .equals() method.
The comparison of i3 and i2 returns true because you're comparing a primitive type (the int i3) with a wrapper class for that primitive type (the Integer i2), so Java unboxes the value of i2 to an int and then compares them (which does work with the == operator).
in first if - you are compare two objects - thay are different. Result = false
in second - you are compare two int values. Result true
in therd - you are compare int and Integer, after unboxing you have two int. Result - true.
for Integer use equals.
The first case, JVM checks whether both i1 and i2 are same reference or not. As they are different so it results false.
The second case, it's no problem as both are primitive data types and have same value, so it's true.
In third case, i2 is first autounboxed and then comparision takes place, so it results true.
With the autocast, (int)i1==(int)i2 will return true, so will (i1==i4)
As the other comments explained it, == only compares the objects (which references are passed by value)
another "safe" and alternative way is using the modulo operation
if ( ( i3%i4)==0) System.out.println("true");

How to compare Integer correctly in Java [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Integer wrapper class and == operator - where is behavior specified?
I known Java integer use cache in -127~128.
If
Integer i = 1;
Integer j = 1;
Integer m = 128;
Integer n = 128;
i == j // true
m == n // false
But I met a strange phenomenon.First,look at following snippet.
List<CustomerNotice> customerNotice = findByExample(example); // use Hibernate findByExample method
for(CustomerNotice n : customerNotice){
if(n.getConfirmStatus() == NoticeConfirmStatus.UNCONFIRMED.getValue()){
// do sth
}
}
public enum NoticeConfirmStatus{
UNCONFIRMED(1), //
CONFIRMED(2), //
FAILED_TO_CONFIRM(3); //
private final Integer value;
private NoticeConfirmStatus(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}
public class CustomerNotice {
#Column(name = "CONFIRM_STATUS")
private Integer confirmStatus;
public Integer getConfirmStatus() {
return this.confirmStatus;
}
public void setConfirmStatus(Integer confirmStatus) {
this.confirmStatus = confirmStatus;
}
}
Although the if expression is not recommended, I think it will be return true,because n.getConfirmStatus()==1, but the result is false.I'm very confusing.
In addition, theList<CustomerNotice> customerNotice acquired by Hibernate findByExample method. Is there some Autoboxing or new operation when retrieve the resultset?
Thank you.
SHORT: (answers question)
If you want to compare Integers as the objects, you should use .equals:
i.equals(j);
m.equals(n);
With this, they should both return true. But if you really want to use ==, you need to get the primitive int value:
i.intValue() == j.intValue();
m.intValue() == j.intValue();
LONG: (explains answer)
The basis of this is that Objects are always stored separately in memory (except for some special cases like m=n), and to be compared properly, they need to be broken down into primitive types that can be compared successfully using ==.
Every Object has a .equals() method, which is inherited from Object as its superclass. However, it must be overridden to do a proper comparison. Integer overrides this method to compare to Integer objects successfully, while using == checks to see if both objects point to the same space in memory, and because two instances of an Object cannot point to the same space in memory, this will always return false.
However, as your code points out, there are some special cases that work, like these:
Your code uses a Integer i = 1, which is considered a "standard instance" and is able to be compared using ==.
If you set one Object equal to another using =, Java tells both objects to point to the same location in memory, which means that == will return true.
There are many others, but those are the two that come to mind and seem relevant.
You'll drive yourself crazy and waste a lot of time trying to figure out specific cases where this works or does not work. It depends on the implementation of code which isn't always visible to you.
The bottom line: never, ever, use == to compare Integer instances, period. As you have seen, it works sometimes, under some circumstances, and fails miserably the rest of the time. If you have a method that returns an Integer, then assign the value to an int, and then you can use == to compare that int to another int.

Comparing two identical strings with == returns false [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am making an archive for my family. There are no syntax errors, however whenever I type in "Maaz", it evaluates realName == "Maaz" to false and goes to the else statement.
import java.util.Scanner;
public class MainFamily {
public static void main (String [] args) {
System.out.println("Enter you're name here");
Scanner name = new Scanner(System.in);//Scanner variable = name
String realName;
realName = name.nextLine();//String variable = user input
System.out.println("Name: "+ realName);
if (realName == "Maaz") {
System.out.println("Name: Maaz");
} else {
System.out.println("This person is not in the database");
}
}
}
TL;DR
You wrote (this doesn't work):
realName == "Maaz"
You meant this:
realname.equals("Maaz")
or this:
realname.equalsIgnoreCase("Maaz")
Explanation
In Java (and many other Object-Oriented programming languages), an object is not the same as a data-type. Data-types are recognized by the runtime as a data-type.
Examples of data-types include: int, float, short.
There are no methods or properties associated with a data-type. For example, this would throw an error, because data-types aren't objects:
int x = 5;
int y = 5;
if (x.equals(y)) {
System.out.println("Equal");
}
A reference is basically a chunk of memory that explicitly tells the runtime environment what that data-block is. The runtime doesn't know how to interpret this; it assumes that the programmer does.
For example, if we used Integer instead of int in the previous example, this would work:
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x.equals(y)) {
System.out.println("Equal");
}
Whereas this would not give the expected result (the if condition would evaluate to false):
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x == y) {
System.out.println("Equal");
}
This is because the two Integer objects have the same value, but they are not the same object. The double equals basically checks to see if the two Objects are the same reference (which has its uses).
In your code, you are comparing an Object with a String literal (also an object), which is not the same as comparing the values of both.
Let's look at another example:
String s = "Some string";
if (s == "Some string") {
System.out.println("Equal");
}
In this instance, the if block will probably evaluate to true. Why is this?
The compiler is optimized to use as little extra memory as is reasonable, although what that means depends on the implementation (and possibly runtime environment).
The String literal, "Some string", in the first line will probably be recognized as equivalent to the String literal in the second line, and will use the same place in memory for each. In simple terms, it will create a String object and plug it into both instances of "Some string". This cannot be relied upon, so using String.equals is always a better method of checking equivalence if you're only concerned with the values.
do this instead
if (realName.equals("Maaz"))
equals() should be used on all non-primitive objects, such as String in this case
'==' should only be used when doing primitive comparisons, such as int and long
use
if(realName.equals("Maaz"))
use == with primitive data type like int boolean .... etc
but if you want to compare object in java you should use the equals method
You have to compare objects with realName.equals ("Maaze"), not with ==.
It is best practice to compare Strings using str.equals(str2) and not str == str2. As you observed, the second form doesn't work a lot of the time. By contrast, the first form always works.
The only cases where the == approach will always work are when the strings are being compared are:
string literals or references to string literals, or
strings that have been "interned" by application-level code calling str = str.intern();.
(And no, strings are not interned by default.)
Since it is generally tricky to write programs that guarantee these preconditions for all strings, it is best practice to use equals unless there is a performance-related imperative to intern your strings and use ==.
Before that you decide that interning is a good idea, you need to compare the benefits of interning with the costs. Those costs include the cost of looking up the string in the string pool's hash table and the space and GC overheads of maintaining the string pool. These are non-trivial compared with the typical costs of just using a regular string and comparing using equals.
You can also use
realname.equalsIgnoreCase("Maaz")
This way you can accept Maaz, maaz, maaZ, mAaZ, etc.
== tests shallow equality. It checks if two objects reference the same location in memory.
Intriguing. Although, as others have stated, the correct way is to use the .equals(...) method, I always thought strings were pooled (irrespective of their creation). It seems this is only true of string literals.
final String str1 = new String("Maaz");
final String str2 = new String("Maaz");
System.out.println(str1 == str2); // Prints false
final String str3 = "Laaz";
final String str4 = "Laaz";
System.out.println(str3 == str4); // Prints true
Since you are working on strings, you should use equals to equalsIngnorecase method of String class. "==" will only compare if the both objects points to same memory location, in your case, both object are different and will not be equal as they dont point to same location. On the other hand, equals method of String class perform a comparison on the basis of the value which objects contains. Hence, if you will use equals method, your if condition will be satisfied.
== compares object references or primitive types (int, char, float ...)
equals(), you can override this method to compare how both objects are equal.
for String class, its method equal() will compare the content inside if they are the same or not.
If your examples, both strings do not have the same object references, so they return false, == are not comparing the characters on both Strings.
It seems nobody yet pointed out that the best practice for comparing an object with a constant in Java is calling the equals method of the constant, not the variable object:
if ("Maaz".equals (realName)) {}
This way you don't need to additionally check if the variable realName is null.
if(realName.compareTo("Maaz") == 0) {
// I dont think theres a better way do to do this.
}

Categories