Reputation: 389
Why not Integer.valueOf(42).equals(Long.valueOf(42))
?
Whether implementation of equals
must be "reflexive, symmetric, transitive, consistent"
but don`t have to be reasonable? :)
Upvotes: 3
Views: 155
Reputation: 1815
A reminder that Integer
and Long
are object wrapper classes of the primitive types int
and long
.
Here is the source code of the equals
method in Integer
(value
here is an int
primitive).
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
And here is the source code of the equals
method in Long
(value
here is a long
primitive).
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
From the source, the equals
method firstly checks if the passed-in obj
is an instance of the corresponding class. If it isn't, equals
skips the check on the primitive value
and returns false
.
So as @Ted Hopp suggested, an Integer
will never test as equal to a Long
(or anything else that's not an Integer
). Comparing primitive values is recommended.
If you nonetheless would like to carry out the equivalence check in the object wrapper setting, then you may wish to widen your Integer (avoiding an overflow) and let the Java compiler do some auto-(un)boxing for you. Something like...
Long theLong = Long.valueOf(42);
Integer theInteger = Integer.valueOf(42);
Long theIntegerInLong = (long) theInteger;
System.out.println(theLong.equals(theIntegerInLong) ? "Equal" : "Unequal");
Upvotes: 1
Reputation: 81159
It would have been possible to define the equality tests among wrapper classes in such a fashion that two wrapper objects that encapsulated the same numerical value would compare equal, regardless of the underlying type. Doing so, however, requires either having all types whose instances may compare equal know about each other, or else requires defining a means via which objects will be able to compare themselves to other objects which haven't even been invented yet. Taking the former approach would mean that even if a new numeric type was capable of representing the value 5, an Integer
which equaled 5 could not report itself equal to an instance of the new type which also represented 5. Taking the latter approach would allow the new object to compare equal to an Integer
with value 5, but would require adding enormous complexity for comparatively little benefit.
Suppose, for example, that one has defined both a BigDecimal
and a BigRational
class; the former stores numbers as a BigInteger
along with a power-of-ten scaling factor; the latter stores a pair of BigInteger
values which represent a reduced-form fraction. One could specify that all numeric values which represent rational numbers should be compared by converting them to BigRational
and comparing the results. Since every rational number would have a unique representation, such a defined method of comparison would behave as an equivalence relation. Unfortunately, it would be horrendously slow. In most cases, it would make more sense to convert comparands into some other form, but trying to identify the best common form for arbitrarily combinations of types would be difficult. It's much easier to simply say being of different types is sufficient justification for the objects to be called "different".
Upvotes: -1
Reputation: 234795
From the docs for Integer.equals()
:
The result is true if and only if the argument is not
null
and is anInteger
object that contains the sameint
value as this object.
In other words, an Integer
will never test as equals()
to a Long
(or anything else that's not an Integer
), regardless of the value being represented. Just compare the primitive values if that's what you're after.
One good reason for not allowing cross-class comparisons is: how would you do it? Suppose you decided to implement Integer.equals()
to test whether the other object was an instance of Number
and compare values using other.intValue()
(which all Number
classes support). The unfortunate result would be that
Integer.valueOf(42).equals(Long.valueOf(((Integer.MAX_VALUE + 1L) << 1) + 42))
would test true
because Long.intValue()
simply casts its value to an int
and
(int) ((Integer.MAX_VALUE + 1L) << 1) + 42)
evaluates to 42 because that's what's in the lower 32 bits. What's perhaps even worse, if you used the same logic for Long.equals()
(where it tested all Number
objects used longValue()
), then the equals()
test would no longer be symmetric.
Upvotes: 5
Reputation: 5755
.equals() is for comparisons between objects in the same inheritance hierarchy, up to and including the ultimate superclass Object. While classes Integer and Long both inherit from java.lang.Number, class Number is apparently missing an .equals() method that compares a Number instance value. Integer and Long's only shared .equals() method is in Object. The Object-to-Object comparison method does not evaluate based on the values of the numbers, hence the seemingly strange result printed.
The documentation for class Integer says: .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." It doesn't handle Long values as more than Objects.
Apparently as per @David_Wallace, other class hierarchies implement .equals() in their superclass. new ArrayList().equals(new LinkedList()) returns true, and both inherit from class java.util.AbstractList which has its own implementation of .equals()
Upvotes: -1