My code did not give the correct result and I begin to troubleshoot and discovered a strange error, can someone explain this to me.
If I pick up the fields and doing this it becomes result1 == false and result2 == true, why?
MyClass m1 = new MyClass();
MyClass m2 = new MyClass();
Field[] fieldsFirst = m1.getClass().getDeclaredFields();
Field[] fieldsSecond = m2.getClass().getDeclaredFields();
for (int i = 0; i < fieldsFirst.length; i++) {
Field first = fieldsFirst[i];
Field second = fieldsSecond[i];
first.setAccessible(true);
second.setAccessible(true);
if(first.get(m1) instanceof Boolean)
{
boolean b1 = (Boolean)first.get(m1);
boolean b2 = (Boolean)second.get(m2);
//Here are the results
boolean result1 = b1 != b2; // false
boolean result2 = (Boolean)first.get(m1) != (Boolean)second.get(m2); // true
}
If I have:
public class MyClass {
private boolean myBoolean = true;
public boolean getMyBoolean()
{
return myBoolean;
}
public void setMyBoolean(booelan inBool)
{
myBoolean = inBool;
}
}
In
boolean result1 = b1 != b2; // false
you are comparing primitive values, as b1 and b2 result from unboxing conversion from Boolean to boolean.
In
boolean result2 = (Boolean)first.get(m1) != (Boolean)second.get(m2); // true
you are comparing references. The result of each get() is referencing a different object. As such, the != comparison is true.
Boolean is a wrapper around the primitive boolean.
a wrapper class wraps (encloses) around a data type and gives it an
object appearance. Wherever, the data type is required as an object,
this object can be used. Wrapper classes include methods to unwrap the
object and give back the data type.
Source: http://way2java.com/java-lang/wrapper-classes/
Just like with other objects, if you need to compare their values, you need to use .equals() and not the comparison operators.
Here:
boolean b1 = (Boolean)first.get(m1);
boolean b2 = (Boolean)second.get(m2);
You are converting the Boolean to boolean. This is called as unboxing conversion which is a part of the AutoBoxing Conversions. These are called Auto because Java automatically does that conversion for you; even if you get rid of the cast.
Hence, you are comparing their primitive values.
Since the primitive values are the same, your comparison evaluates to true. Hence, false
Here:
boolean result2 = (Boolean)first.get(m1) != (Boolean)second.get(m2);
You are comparing the references of the two objects. Since they are stored in different memory locations, the result of the comparison is true. Intuitive, isn't it? Different object, different memory location?.
If you really need to compare the values of two objects, use the equals() methods. In case of Wrapper objects however, close your eyes, unbox them to their primitive values and then compare.
Just like Josh Bloch suggests in Effective Java: Comparing Wrappers? Unbox the suckers!!
Just more from Effective Java, comparison operators work in case of Wrapper class if they have a greater than or less than sign attached to them. <, <=, >, >= yield the correct result even if you do not unbox. == and != do not yield correct result
The comparation boolean result1 = b1 != b2 is a primitive value comparation, so you can use operators like == or !=.
The comparation boolean result2 = (Boolean)first.get(m1) != (Boolean)second.get(m2) is an object comparation, so you are not comparing values, but references. You should compare them by using equals()
Like boolean result2 = ((Boolean)first.get(m1)).equals((Boolean)second.get(m2))
Related
Any array in java is Object. hence it has equals method. But I cannot watch realization of this method(or maybe is it possible ?)
I wrote several examples and always == and equals returns similar results.
Is there way when == and equals return different results ?
There is difference
1)
int[] a1 = {};
long[] a2 = {};
boolean r1 = a1.equals(a2); // returns false
boolean r2 = a1 == a2; // compile time error
2)
int[] a1 = null;
int[] a2 = {};
boolean r1 = a1.equals(a2); // throws NPE
boolean r2 = a1 == a2; // returns false
I don't think so this is the equalsmethod :
public boolean equals(Object obj) {
return (this == obj);
}
And it internally uses == operator for comparison.
You can view the javaDoc here.
Just write this testin a test class
#Test
public void testArray() {
int[] A = {1,2};
int[] B = {1,2};
assertTrue(Arrays.equals(A, B));
assertTrue(A.equals(B));
assertTrue(A == B);
}
In general "==" compares the addresses while .equals() will compare using the object equals which depends on the objects (comparing to File object is different than comparing to Integers).
EDIT:
My bad, this is actually wrong,
== and equals are actually the same in java as seen there:
equals vs Arrays.equals in Java
In case of arrays, it is indeed the same, and quite confusing I must say.
I modified my test to show the difference.
So I've heard that if I compare 2 strings with == then I will only get true back if they both refer to the same object/instance. That's strings. What about Booleans?
Does == check for full equality in Booleans? - Java
It depends on whether you're talking about Booleans (the object wrapper, note the capital B) or booleans (the primitive, note the lower case b). If you're talking about Booleans (the object wrapper), as with all objects, == checks for identity, not equivalence. If you're talking about booleans (primitives), it checks for equivalence.
So:
Boolean a, b;
a = new Boolean(false);
b = new Boolean(false);
System.out.println("a == b? " + (a == b)); // "a == b? false", because they're not the same instance
But
boolean c, d;
c = false;
d = false;
System.out.println("c == d? " + (c == d)); // "c == d? true", because they're primitives with the same value
Regarding strings:
I've heard that if I compare 2 strings with == then I will only get true back if the strings are identical and they both refer to the same object/instance...
It's not really an "and": == will only check whether the two String variables refer to the same String instance. Of course, one String instance can only have one set of contents, so if both variables point to the same instance, naturally the contents are the same... :-) The key point is that == will report false for different String instances even if they have the same characters in the same order. That's why we use equals on them, not ==. Strings can get a bit confusing because of interning, which is specific to strings (there's no equivalent for Boolean, although when you use Boolean.valueOf(boolean), you'll get a cached object). Also note that Java doesn't have primitive strings like it does primitive boolean, int, etc.
If you have an Object use equals,
when not you can run in things like this.
(VM cache for autoboxing primitives)
public static void main(String[] args){
Boolean a = true;
Boolean b = true;
System.out.println(a == b);
a = new Boolean(true);
b = new Boolean(true);
System.out.println(a == b);
}
the output is TRUE and FALSE
When using ( == ) with booleans,
If one of the operands is a Boolean wrapper, then it is first unboxed
into a boolean primitive and the two are compared.
If both are Boolean wrappers,created with 'new' keyword, then their
references are compared just like in the case of other objects.
new Boolean("true") == new Boolean("true") is false
If both are Boolean wrappers,created without 'new' keyword,
Boolean a = false;
Boolean b = Boolean.FALSE;
// (a==b) return true
It depends if you are talking about value types like: int, boolean, long or about reference types: Integer, Boolean, Long. value types could be compared with ==, reference types must be compared with equals.
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().
Why does the code below return false for long3 == long2 comparison even though it's literal.
public class Strings {
public static void main(String[] args) {
Long long1 = 256L + 256L;
Long long2 = 512L;
Long long3 = 512L;
System.out.println(long3 == long2);
System.out.println(long1.equals(long2));
}
}
Long is an object, not a primitive. By using == you're comparing the reference values.
You need to do:
if(str.equals(str2))
As you do in your second comparison.
Edit: I get it ... you are thinking that other objects act like String literals. They don't*. And even then, you never want to use == with String literals either.
(*Autobox types do implement the flyweight pattern, but only for values -128 -> 127. If you made your Long equal to 50 you would indeed have two references to the same flyweight object. And again, never use == to compare them. )
Edit to add: This is specifically stated in the Java Language Specification, Section 5.1.7:
If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
Note that long is not specifically mentioned but the current Oracle and OpenJDK implementations do so (1.6 and 1.7), which is yet another reason to never use ==
Long l = 5L;
Long l2 = 5L;
System.out.println(l == l2);
l = 5000L;
l2 = 5000L;
System.out.println(l == l2);
Outputs:
true
false
You could also get the primitive value out of the Long object using:
str.longValue()
If you want to do
str3==str2
do like this..
str3.longValue()==str2.longValue()
This serves your purpose and much faster because you are comparing two primitive type values not objects.
Here Long is a Wrapper class so the below line will compare the reference not the content.
long3 == long2
its always better to compare with ** .longValue() ** like below
long3.longValue() == long2.longValue()
If we use in-build equal() method that also will do the same thing with null check.
long3.equals(long2)
Below is the internal implementation of equals() in java
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
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.