This question already has answers here:
The equals() method in Java works unexpectedly on Long data type
(10 answers)
Closed 8 years ago.
Integer a = new Integer(1);
Integer b = new Integer(1);
Long c = new Long(1);
System.out.println(a.equals(b));
System.out.println(a.equals(c));
Question is why does a.equals(c) gives a false?
From Integer.equals():
The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
c is not an Integer, so a.equals(c) returns false.
Because, you are using Integer class's equals method which does follows:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
The condition fails here if (obj instanceof Integer) as the obj i.e. c in your case is an instance of Long.
because both object are not of same Class one is Integer and other is Long, it will not only compare values when you say .equals()
The equals of Integer (and most classes) start with checking if the class of the parameter is equal to the objects own class. If not, equals will return false. This makes more sense if you would try to call equals between an integer and a string, they cannot be compared on values the same way as integer and long can. Therefore, all classes that are not integer and are calling equals on an integer object will return false.
if you look at the source of Integer.equales(Object obj) you'll see why:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Long is not an instance of Integer.
In short: because c is not an Integer object. You're calling Integer#equals(Object) and passing a Long in as the parameter. The source code for Integer#equals(Object) is:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Because obj is a Long and not an Integer, the if (obj instanceof Integer) check fails and the method then returns false.
Related
As we know that == in case of Objects returns true if pointing to the same reference else it returns false.
So , if i have taken
Integer a = new Integer("1"); // Creating Integer Object a
Integer b = new Integer("1"); // Creating Integer Object b
and then perform a == b , then it returns true
but they both have different references.
The JVM caches integer values between -127 to 127.
That's the reason == works for Integer value between this range.
But:
Integer i1=new Integer("11");
Integer i2=new Integer("11");
System.out.println(i1==i2); //false
Integer i3=11;
Integer i4=11;
System.out.println(i3==i4); //true
Integer i5=128;
Integer i6=128;
System.out.println(i5==i6); //false
Because it is overridden. source:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Let me more elaborate on this, #asAmit Bhati said in his answer when we write
Integer i1=new Integer("11");
Integer i2=new Integer("11");
System.out.println(i1==i2); //false
jvm creates two separate objects and comparing them with "==" results in false. but when we write the following code:
Integer i3=11;
Integer i4=11;
System.out.println(i3==i4); //true
it will be translated into this:
Integer i3=Integer.valueOf(11);
Integer i4=Integer.valueOf(11);
Implementation of valueOf method is as follow(in java 1.8):
public static Integer valueOf(int var0) {
return var0 >= -128 && var0 <= Integer.IntegerCache.high?Integer.IntegerCache.cache[var0 + 128]:new Integer(var0);
}
as you can see if the value is between -128 and Maximum cache value (which can be configured using this jvm parameter -Djava.lang.Integer.IntegerCache.high), it will retrieve the cached value and doesn't create a new instance of Integer that is why (==) returns true for certain values!
also note that the same goes for Character Wrapper class but not for Float and Double classes.
As the answer above says, it may work in many cases, nevertheless you shouldn't compare two Integer with == since it may present problems in some cases.
Check this answer for more information:
Comparing Integer values in Java, strange behavior
If you check equals method implementation in Integer class it is:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
From here you can see it uses "==" operator.
Now the reason behind it. Ultimately you have to compare value of the Integer wrapper class, which will happen automatically because of autoboxing and unboxing in Java.
And also from the method definition you can see that it is retrieving passed Object value using ((Integer)obj).intValue().
With JSONObject you can make:
JSONObject.NULL.equals(null); //returns true
JSONObject.NULL breaks Object.equals() contract, at least it seems like it does, since
For any non-null reference value x, x.equals(null) should return false
The fact that this class is so widely used and supported makes me think that there is no violation for some reason, is there?
The NULL-Object is a pattern that is used to avoid checks like if(object == null).
It is the same thing here. The NULL is just a name. But what do you really have is not actually null (null-reference) but an object that gives a default-behavior (not-null reference).
It clearly violates the Object.equals() since
JSONObject.NULL is not null but a new Object()
Return value is true instead of false
JSONObject.NULL from source looks like below & the value is not null.
public static final Object NULL = new Object() {
#Override public boolean equals(Object o) {
return o == this || o == null; // API specifies this broken equals implementation
}
#Override public String toString() {
return "null";
}
};
equals() from Object looks like
public boolean equals(Object o) {
return this == o;
}
The additional comparison of o == null in JSONObject.NULL equals() method will always return true if we pass null. Hence
JSONObject.NULL.equals(null); //Will return true
I am having a problem with overriding equals method in one class, this class has only one attribute which is a 2-dimensional array called grid. This is the constructor:
public World(int n, int m){
this.grid = new Object[n][m];
}
The equals method:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (null == obj)
return false;
if ( !obj instanceof World)
return false;
World other = (World) obj;
if ( !Arrays.deepEquals(grid, other.grid))
return false;
return true;
}
I have already overridden the hashCode() method as well, but the problem is that doesn't matter the case, the equals is always returning true. Does anyone know what is wrong?
Be careful - you're messing with Object here.
Regardless of the actual objects you place into that array, they will all be using Object#equals for its comparison. The reason for that lies in the documentation of Arrays#deepEquals.
Two possibly null elements e1 and e2 are deeply equal if any of the following conditions hold:
e1 and e2 are both arrays of object reference types, and Arrays.deepEquals(e1, e2) would return true
e1 and e2 are arrays of the same primitive type, and the appropriate overloading of Arrays.equals(e1, e2) would return true.
e1 == e2
e1.equals(e2) would return true.
And...guess what Object#equals does:
public boolean equals(Object obj) {
return (this == obj);
}
Your arrays will only ever be equivalent if and only if they contain the exact same instances of stuff between them.
Applying stricter types around your array, such as a concrete class, may help you to get around the issue. We don't know what you're storing in that array, so I can't suggest anything concrete, but look to move away from Object.
Try this-
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof World)) {
return false;
}
World other = (World) obj;
if (!Arrays.deepEquals(this.grid, other.grid))
return false;
return true;
}
What precisely do the last four lines of the following code do?
class Money {
private int fAmount;
private String fCurrency;
public Money(int amount, String currency) {
fAmount = amount;
fCurrency = currency;
}
public int amount() { return fAmount; }
public String currency() { return fCurrency; }
public Money add(Money m) {
return new Money(amount() + m.amount(), currency());
}
public boolean equals(Object anObject) {
if (anObject instanceof Money) {
Money aMoney= (Money)anObject;
return aMoney.currency().equals(fCurrency) && aMoney.amount() == fAmount;
}
return false;
}
They check for equality of two money objects. It checks if the parameter passed to equals is indeed a money object and then checks if the value and currency are equal
if (anObject instanceof Money) {
Is the object a Money Object? true or false
Money aMoney= (Money)anObject;
The object is a Money object. Cast the object to a Money object so we can access all of its Money-like fields and methods
return aMoney.currency().equals(fCurrency) && aMoney.amount() == fAmount;
Compare some Money things and return true or false
return false;
The object is not a Money object. Return false
I'll take it from here:
public boolean equals(Object anObject) {
if (anObject instanceof Money) {
Money aMoney= (Money)anObject;
return aMoney.currency().equals(fCurrency) && aMoney.amount() == fAmount;
}
return false;
}
What you have here is a method.
public boolean equals(Object anObject) {
Declares that this method is publilc, should return a boolean, and takes an Object as an arguement.
if (anObject instanceof Money) {
This line compares the object which is passed in as an argument, to the Class you've created called Money. the call "instanceof" returns true or false, and determines if the Objecct is an Instance of the Money Class.
Money aMoney= (Money)anObject;
This line allocates a portion of memory, and identifies the Object in that space as an object of Class Money. It then takes the object passed into the Method and Casts it to the Money Class. This only occurs if the preceding line (instanceof) returns true. If you did this without the prior check you might get an exception, say if you passed in a String.
return aMoney.currency().equals(fCurrency) && aMoney.amount() == fAmount;
Now that you have an object which is the type Money, you can use methods which are declared in the Money class. These include the method currency() and amount(). What you are doing here is retreiving the values for currency in the passed in object to some constant value (fCurrencY) and amount() to some other value (fAmount). You check to determine their equivlance, and return the truth result of ANDing the results of the two comparisons together.
You could rewrite this line as:
boolean currencyEqual = aMoney.currency().equals(fCurrency); // string and or object comparison for equivlance
boolean amount = aMoney.amount() == fAmount; // numeric comparison
boolean bothEqual = currencyEqual && amount; //boolean AND operation (1 && 1 = 1, 1&&0 = 0, 0 && 0 = 0)
return bothEqual;
The final line:
return false;
Only runs if the passed in argument is not an instanceof Money, and thus you return false.
For a very good description of instanceof:
What is the 'instanceof' operator used for?
For a discussion of method declarations:
http://docs.oracle.com/javase/tutorial/java/javaOO/methods.html
for inheritance trees and casting:
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
When comparing not primitive data type (that is not int, double, boolean, etc.) with == you are not comparing their values, but their references. That means you are basically comparing if they point to the same block of memory. To compare the values of these objects you need to override the method equals in their class.
You can see in your example code that String also uses equals, not ==, because String is also not primitive type.
I have below Findbugs error for my "equal" method,
This class defines an equals method
that overrides an equals method in a
superclass. Both equals methods
methods use instanceof in the
determination of whether two objects
are equal. This is fraught with peril,
since it is important that the equals
method is symmetrical (in other words,
a.equals(b) == b.equals(a)). If B is a
subtype of A, and A's equals method
checks that the argument is an
instanceof A, and B's equals method
checks that the argument is an
instanceof B, it is quite likely that
the equivalence relation defined by
these methods is not symmetric.
I can not post the code here for security violataion. Please let me know what is the error?
It says that the contract of equals() implies that, a.equals(b) is true if and only if b.equals(a) is true.
If B extends A, in A.equals(Object obj) you probably will have
if !(obj instanceof A) return false;
and in B.equals(Object obj) you will have
if !(obj instanceof B) return false;
Here is the asymmetry: an instance of B makes (b instanceof A) true, while an instance of A makes (a instanceof B) false. So it means a risk than a.equals(b) is true and b.equals(a) is false.
You can use the similar construction to prevent this error:
public boolean equals(final Object obj)
{
if (obj == null || getClass() != obj.getClass())
{
return false;
}
// ...
instead of
public boolean equals(final Object obj)
{
if (!(o instanceof UniversalIDDefinition))
{
return false;
}
// ...
You can use this too :
if (obj == null || !MyClass.class.isAssignableFrom(obj.getClass())) {
return false;
}