When I want to compare two variables(One type Object, one type Long), I found that cannot convert Object to Long, for example:
Object obj = 100;
Long l_num = 100L;
System.out.println(obj.equals((Object)l_num)); // print false
System.out.println(((Long)obj) == l_num); // throw java.lang.ClassCastException Exception
Then I can only compare the two with (obj.toString()).equals(l_num.toString()), it returns true.
But, the result is different when I compare Integer with Object:
Object obj = 100;
Integer i_num = 100;
System.out.println(((Integer)obj) == i_num); // return true
System.out.println(obj.equals(i_num)); // return true
System.out.println((obj.toString()).equals(i_num.toString())); // return true
Is there someone kindly tell me why two results are different and is there any method better to compare Object with Long ?
If it's a meaningful question you think, let's talk about it. Thanks.
Long and Integer are different types. you compared objects of different types.
100 is int. So it is boxed to Integer. So obj and i_num can be compared.
Its preety straight forward -
Object obj = 100;
This 100 is an integer and Object obj hold that integer reference, you can make sure by System.out.println(obj.getClass()); which prints class java.lang.Integer. And It is a example of auto boxing -
System.out.println(((Long)obj) == l_num);
(Long)Obj throws the ClassCastException as it is trying to cast Integer object to Long object which is invalid.
write form would be -
System.out.println(((Long)((Integer)obj).longValue()) == l_num); // it return true
Related
I am trying to compare two Object whose type is unknown during runtime, but it is at least guaranteed that the type will be some form of Number. Is there a way to compare an Object whose base class is Number without explicitly casting the object to one of Java's integral types?
So, for example:
Object objectInt1 = (Integer) 5;
Object objectInt2 = (Integer) 6;
if (objectInt1 > objectInt2) {
// Clearly won't compile
}
if ((Number) objectInt1 > (Number) objectInt2) {
// This of course won't compile either
}
The only way I can think to accomplish this is by using instanceof and check for each integral type, and do explicit casting. But maybe there is a cleaner way to do this.
If you know they will be Number, you can use:
Object object1 = Integer.valueOf(5);
Object object2 = Float.valueOf(6);
Number number1 = (Number) object1;
Number number2 = (Number) object2;
if (number1.doubleValue() < number2.doubleValue()) {
System.out.println("number1 < number2");
}
Of course you can also do your casting inline.
There are only two “integral” types of Number: Integer and Long, and an Integer can safely be expressed as a Long.
The Number type has the longValue() method, so you can safely cast to Number and compare the result of calling that method:
if (((Number)object1).longValue() > ((Number)object2).longValue())
To compare something you must know how to do it. So you cant just take something unknown and compare it to something else.
Operators < > are defined for primitive types only.
Objects that are meant to be compared implement Comparable interface. You can check that Object implements it and call compareTo method to compare Objects of the same type. All common java number types (Integer, Short, BigDecimal) implement Comparable.
This question already has answers here:
How can I properly compare two Integers in Java?
(10 answers)
Closed 5 years ago.
I have the following code:
public class Test {
public static void main(String[] args) {
Integer alpha = new Integer(1);
Integer foo = new Integer(1);
if(alpha == foo) {
System.out.println("1. true");
}
if(alpha.equals(foo)) {
System.out.println("2. true");
}
}
}
The output is as follows:
2. true
However changing the type of an Integer object to int will produce a different output, for example:
public class Test {
public static void main(String[] args) {
Integer alpha = new Integer(1);
int foo = 1;
if(alpha == foo) {
System.out.println("1. true");
}
if(alpha.equals(foo)) {
System.out.println("2. true");
}
}
}
The new output:
1. true
2. true
How can this be so? Why doesn't the first example code output 1. true?
For reference types, == checks whether the references are equal, i.e. whether they point to the same object.
For primitive types, == checks whether the values are equal.
java.lang.Integer is a reference type. int is a primitive type.
Edit: If one operand is of primitive type, and the other of a reference type that unboxes to a suitable primitive type, == will compare values, not references.
Integer objects are objects. This sounds logical, but is the answer to the question. Objects are made in Java using the new keyword, and then stored in the memory. When comparing, you compare the memory locations of the objects, not the value/properties of the objects.
Using the .equals() method, you actually compare the values/properties of objects, not their location in memory:
new Integer(1) == new Integer(1) returns false, while new Integer(1).equals(new Integer(1)) returns true.
ints are a primitive type of java. When you create an int, all that is referenced is the value. When you compare any primitive type in Java, all that is compared is the value, not the memory location. That is why 5 == 5 always returns true.
When you compare an Integer object to a primitive type, the object is cast to the primitive type, if possible. With an Integer and an int this is possible, so they are compared. That is why Integer(1).equals(1) returns true.
What you'll use new Integer(1) to create new object, it creates a totally different object each time even though it has the same value. The '==' checks if the objects are same, not data values. In your case, you could have checked the value as follows :
if(alpha.intValue() == foo.intValue()) {
//
}
Integer == int here auto boxing applied ( so Integer converted to int before comparision) so true.. but Integer == Integer here object comparison so as reference are different so false..
First example:
Using the == operator between objects checks for reference equality, and since you are comparing two different objects they do not equal.
Second example:
When using the == between a wrapper type (Integer, Long, etc.) and a numeric type (int, long, etc.) the wrapper type is unboxed and the equality check is done between the two primitive numeric types (I.e. between int and int). The unboxing is part of binary numeric promotion, read more here: http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2
Consider two references of type Integer that call the static factory method valueOf as shown below:-
Integer a = Integer.valueOf("10");
Integer b = Integer.valueOf("10");
Considering that Integer is immutable, is it ok to compare a and b using == instead of using equals method. I am guessing that the valueOf method makes sure that only one instance of Integer with the value 10 is created and a reference to this instance is returned for every Integer created with a value 10.
In general, is it ok to compare two references of an immutable class that are created using a call to the same static factory method by using == instead of equals?
Edit:
The Integer class was used just as an example. I am aware thar Intgers upto 127 will return true if they are compared using ==. What i need to know is that when l create my own immutable class, say MyImmutable with a method create() that will ensure that no duplicate MyImmutable objects are created, will it be ok if I compare 2 MyImmutable references created using the create method by using == instead of equals.
No, that's not safe in general. The == operator compares the references, not the values.
Using == happens to work for integers between -128 and 127, but not for other integers. The following code demonstrates that == won't always work:
Integer a = Integer.valueOf(10);
Integer b = Integer.valueOf(10);
System.out.println(a == b);
true
Integer c = Integer.valueOf(1000);
Integer d = Integer.valueOf(1000);
System.out.println(c == d);
false
See it working online: ideone
The explanation for this behaviour lies in the implementation of Integer.valueOf:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
source
Not also that the standard requires that boxing integers for small inputs (-128 to 127) gives objects with equal references.
5.1.7 Boxing Conversion
If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
However the standard makes no such guarantees for integers outside this range.
In general, is it ok to compare two references of an immutable class that are created using a call to the same static factory method by using == instead of equals?
As shown above, it won't work in general. But if you ensure that two immutable objects with the same value always have the same reference, then yes, it could work. However there are some rules you must follow carefully:
The constructor must not be public.
Every object you create via the static method must be cached.
Every time you are asked to create an object you must first check the cache to see if you have already created an object with the same value.
== and equals() is fundamentally different.
You should read this post for more details:
Difference between Equals/equals and == operator?
It has nothing to do with immutable objects.
If your factory method returns the same object for equal inputs, it's safe to compare them with ==. For example String.intern works this way. Enums are also could be compared with ==. But Integer.valueOf returns the same object only for -128 ... 127 range (in default configuration).
Integer.valueOf(127) == Integer.valueOf(127)
but
Integer.valueOf(128) != Integer.valueOf(128)
Generally speaking you should use equals method to compare any objects. Operator == could be used to improve performance, when there are small number of different values for object. I wouldn't recommend to use this method, unless you are 100% sure in what you are doing.
Immutability and equality do not necessarily have something to do with each other. == compares for reference equality, that means, it compares if both variables point to the very same instance of the object. Equality means that both objects share the same value. Immutability now means that you can not alter an object after its construction.
So, you might have two immutable obejcts, that represents the same value (meaning, they are equals so that a.equals(b) returns true) but that are not the same instance.
I have a little example for you here:
public class MyPoint {
private int x;
private int y;
public MyPoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof MyPoint))
return false;
MyPoint p = (MyPoint) obj;
return this.x == p.x && this.y == p.y;
}
/**
* #param args
*/
public static void main(String[] args) {
MyPoint p = new MyPoint(2, 2);
MyPoint q = new MyPoint(2, 2);
MyPoint r = q;
System.out.println(p == q);
System.out.println(p == r);
System.out.println(q == r);
System.out.println(p.equals(q));
System.out.println(p.equals(r));
System.out.println(q.equals(r));
}
}
The output is:
false
false
true
true
true
true
MyPoint is immutable. You can not change its values / its state after is has been initialized. But, as you can see, two objects of myPoint might be equal, but they might not be the same instance.
I think what you have in mind is some kind of flyweight pattern, where only one object exists for every possible state of the object. Flyweight also means commonly that those obejcts are immutable.
They are not the same object, so == will not be true. With objects, be safe and use equals().
The title is pretty self-explanatory. I'm moving from C# to Java. I have an object and a getter method which returns its ID. I want to compare the ids of two objects of the same type and check if the values of their ids are equal.
tried:
obj.getId() == obj1.getId();
Long id1 = obj.getId();
Long id2 = obj1.getId();
assertTrue(id1.equals(id2))
assertTrue(id1== id2)
In java:
the == operator tells you if the two operands are the same object (instance).
the .equals() method on Long tells you if they are equal in value.
But you shouldn't do either. The correct way to do it is this:
assertEquals(id1, id2);
With assertEquals(), if the assertion fails, the error message will tell you what the two values were, eg expected 2, but was 5 etc
To compare two primitive long you can simply use ==
Example:
long x = 1L;
long y = 1L;
if (x == y) {
System.out.println("value of x and y are same");
}
To compare two Long objects you can use Long.compare(long x, long y). This method was added in java 1.7. Below is the method implementation:
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
Example:
Long x = new Long(1);
Long y = new Long(1);
if (Long.compare(x,y) == 0) {
System.out.println(values of x and y are same);
}
in java,
use == to compare primitives and x.equals(y) to compare objects.
I'm not sure what your question is-- it looks like you tried both, and did neither work?
Note, you are using Long instead of long, so you want to use .equals()
(long is a primitive, Long is an object)
Try doing the following:
assertTrue(id1.longValue() == id2.longValue())
They must not be equal using ==. Use either:
id1.equals(id2)
or
id1.longValue() == id2.longValue()
In both cases I left out null-checks because I doubt you'd forget them, if they were needed here ;)
So, why is Long not always == another Long with the same value? The answer is easy. They're different objects! Depending on how the Long was retrieved they might be the same, because of internal caching. See Long.valueOf.
In addition to all the comments about the right comparison, strong typing can help you resolve your issue.
Does getID() return something of type Long (that's a class type) or of type long (that's a primitive type)? The problem is that if the method returns a primitive value, then comparing with '==' and 'equals()' will both work, because Java automatically casts primitives into wrapper objects when you need them.
But the other way, if getID() returns a Long value, comparing with '==' is likely to fail, because that checks if you have the same object, not if the objects have the same value.
You need to be aware of the difference between Long and long - long is the primitive type, Long is the wrapper type. (A bit like a boxed value in C#, but strongly typed.) What's the return type of getId()?
Simply:
assertEqual(id1, id2);
should be fine if you're doing this in a test. Otherwise, you could use:
if (id1.equals(ids2))
if they're definitely not null, or use Guava:
if (Objects.equal(id1, id2))
to handle nullity. (You can write Objects.equal yourself, of course, but you should definitely get hold of Guava anyway, so you might as well use that...)
It's worth noting that certain wrapper objects are reused - so for example:
// This will work
Long x = 5L;
Long y = 5L;
assertTrue(x == y); // Reference comparison
// This *probably* won't but it could!
x = 10000L;
y = 10000L;
assertTrue(x == y); // Reference comparison
Let's first consider the following expressions in Java.
Integer temp = new Integer(1);
System.out.println(temp.equals(1));
if(temp.equals(1))
{
System.out.println("The if block executed.");
}
These all statements work just fine. There is no question about it. The expression temp.equals(1) is evaluated to true as expected and the only statement within the if block is executed consequently.
Now, when I change the data type from Integer to Long, the statement temp1.equals(1) is unexpectedly evaluated to false as follows.
Long temp1 = new Long(1);
System.out.println(temp1.equals(1));
if(temp1.equals(1))
{
System.out.println("The if block executed.");
}
These are the equivalent statements to those mentioned in the preceding snippet just the data type has been changed and they behave exactly opposite.
The expression temp1.equals(1) is evaluated to false and consequently, the only statement within the if block is not executed which the reverse of the preceding statements. How?
You're comparing a Long to an int. The javadoc for java.lang.Long#equals says that the equals method
Compares this object to the specified object. The result is true if and only if the argument is not null and is a Long object that contains the same long value as this object.
Instead try System.out.println(new Long(1).equals(1L)); Now that you're comparing a Long to a Long instead of a Long to an Integer, it will print true.
The reason you can do that comparison is because of autoboxing in Java.
The actual method you are calling is this:
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Long.html#equals(java.lang.Object)
which is comparing your Long object to some other Object, not to an actual primitive int.
What happens when you call the method is that your primitive integer(1) is being autoboxed into an Object(Integer) so then you are effectively calling:
new Long(1).equals(new Integer(1));
which is why it fails.
This is why if you call
new Long(1).equals(1L)
this would work, because Java will autobox the 1L (primitive long, not int) into a Long object, not an Integer object.
The literal value 1 is not a long, it's an int. Try the above code with this instead:
System.out.println(temp1.equals(1L));
And
if (temp1.equals(1L))
As you can see, putting an L after the literal value 1 indicates that it's a long, and then the comparisons work as expected.
Java is being lazy.
When you perform the following comparison java will automatically cast the int to a long (as a long can contain any value an int can contain). And the comparison is between two longs and not two ints.
int i = 1;
long l = 1L;
boolean b = i == l;
Java is able to do this because the type information about i and l is known at compile time and when performing the comparison. However, when you use the boxed version the type can be known at compile time, but not when performing the comparison. This is because the comparison has to done within an equals method, and since equals takes Object as a parameter the type information is lost. Thus Java is lazy and only checks to see if two boxed numbers are equal if they are both of instances of same Number class (eg. both Integer, or both Long, or both Double, etc...).
Turns out the only fully reliable way to compare two numbers of unknown type at runtime is to convert both to strings and both to BigDecimal and then to use the method compareTo (and not equals). Though if you know you are only ever going to get longs and ints then life is simpler as you can just do the following.
Number n0 = new Long(1L);
Number n1 = new Integer(1);
boolean equal = n0.longValue() == n1.longValue();
According to Javadoc's page on Long, the .equals method evaluates to true only if
The argument is a Long object
If (1) is true, then the Long objects must have equal values
In your scenario, 1 is an int, not a Long object, so it fails (1), and therefore, evaluates to false. If you need to test to a long, use 1L instead.
That behaviour is consistent with autoboxing converting the 1 to an Integer which then compares equal to another Integer(1). Comparing a Long to an Integer yields false.
If you would use 1L to compare against Long it would yield true.
Long temp1 = new Long(1); System.out.println(temp1.equals(1));
if(temp1.equals(1)) {
System.out.println("The if block executed."); }
in this code temp1.equals(1) is comparing a Long object to Integer object which gives the result false ,we can correct it by using 1L instead of 1 ,,,eg temp1.equals(1L), by doing this we are comparing Long object with a Long and gives result TRUE
The implementation of equals() method of class Long illustrates why:
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
The equals method in Java.lang.Long initially starts with an instanceOf Long check only after that the value is compared.
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
So if you are going to use and Integer Value int the place of a Long value then the first check fails and hence you will get false as the result .
You can compare Long/integer values without uting equals(). This is only needed when you are comparing strings as far as I know.