I have written a piece of Java code which is running in an infinite loop.
Below is the code:
public class TestProgram {
public static void main(String[] args){
Integer i = new Integer(0);
Integer j = new Integer(0);
while(i<=j && j<=i && i!=j){
System.out.println(i);
}
}
}
In the code above, while seeing the condition in the while loop, at first it looks like that program will not go inside the while loop. But actually it is an infinite loop and keeps printing the value.
What is happening here?
i <= j is evaluated to true, because auto unboxing happens for int
comparisons and then both i and j hold the default value, 0.
j <= i is evaluated to true because of the above reason.
i != j is evaluated to true, because both i and j are
different objects. And while comparing objects, there isn't any need of
auto unboxing.
All the conditions are true, and you are not changing i and j in loop, so it is running infinitely.
Because you are comparing
0 < = 0 (true) // unboxing
0 > = 0 (true) // unboxing
reference != secondReference (true) as you are creating objects, not a primitive comparison. So it evaluates to while(true) { // Never ending loop }.
The integer objects are different. It is different from the basic int type.
See this answer: How to properly compare two Integers in Java?
The i != j part is true, which you were expecting to be false.
There are two different cases which we have to understand first,
case 1:
Integer i = new Integer(10);
Integer j = new Integer(10);
System.out.println((i<=j && j<=i && i!=j));
System.out.println(i!=j);
case 2:
Integer i = 10;
Integer j = 10;
System.out.println((i<=j && j<=i && i==j));
System.out.println(i==j);
both are different, as
in case 1: i!=j will be true because both referencing to two different object in heap and can't be same. But
in case 2: i==j will be true because both 10 are integer literals and Java maintains pool for Integer literals which have value (-128 <= X <= 127). So, in this case 10<=127 results true, So both will have reference to same object.
The loop is not ending because your condition is true( i != j is true because there are 2 different objects, use Integer.valueOf instead) and inside the loop the values are not changing so your condition remains true forever.
Perhaps the reason is that both 'i' and 'j' are objects, and object comparison is not the same as object reference comparison. Please consider using !i.equals(j) instead of i!=j
The integer objects are different. It is different from the basic int type.
so you can just do like that. what you do it's just compare the object and of course the result is true.
Integer a = new Integer(0);
Integer b = new Integer(0);
The <= and >= comparisons will use the unboxed value 0, while the != will compare the references and will succeed since they are different objects.
Even this will also works i,e
Integer a = 1000; Integer b = 1000;
but this doesnot :
Integer a = 100; Integer b = 100;
The reason is because Integer internally uses caching for Integer objects between -128 and 127 and return instances from that cache for the range it covers. I am not sure but I guess you can also change its maximum value in package "java.lang.Integer.IntegerCache.high".
For better understanding check url : https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching
The program keeps on displaying the same value of i because you aren't incrementing or decrementing either the value of i or j. The condition in the for always keeps evaluating to true, so it is an infinite loop.
you have to know its a bit different in && this and this & when you use && then when first condition is true then it check second condition if its false then it not checked third condition because in & operator if one condition is false all of the statement is false if use || then if it see true then it return true in your code because i and j is equal first and second condition are true then in third condition it will be false because they are equal and while condition is false .
Related
Integer i = new Integer(0);
Integer j = new Integer(0);
while(i <= j && j <= i && i !=j ){
System.out.println(i);
}
Why does this while loop execute?
I understand that i != j. But separately, both i <= j and j <= i returns true. Why? And doesn't that mean that i == j? In that case the while loop shouldn't execute even once. But it goes for an infinite loop. Why is this so?
While == can be performed between two references (and is, when both sides are Integer), <= can't - so the compiler unboxes. So, your code is equivalent to:
while (i.intValue() <= j.intValue() &&
j.intValue() <= i.intValue() &&
i != j)
Now when i and j refer to different Integer objects with the same value, all of those conditions will be met - hence the loop keeps executing.
Try:
while(!i.equals(j))
You are comparing two integer objects with == rather than two primitive int values. That is to say, "Integer" is an object while int is a primitive value. Doing != on an object will return true for Integer(0) and Integer(0) because they are indeed not equal -> each has a separate location in memory.
The "new" operator allocates dynamic memory on the heap.
For == to work, you could change the type to int, as in:
int i = 0;
int j = 0;
This will compare the values directly.
If you use "Integer," another alternative is to use the .compareTo method, which will compare the value of the objects
== for objects, like a capital-I Integer, compares references. <= and >= will unbox the Integer objects and compare the values numerically, which is completely different.
Think of == and != in this case as completely unrelated to the values of the Integers.
"<=" is comparing the values while "!=" the references hence here all the cases are true hence it is going in infinite loop.
I understand that the values of the two would be the same (say 3 to 4). However, does the computer see the two as the same, and would they both be considered expressions?
Thanks in advance!
Yes to both, except that (value++) evaluates to the old value, whereas (value = value + 1) evaluates to the new value.
The direct equivalent of (value = value + 1) within an expression is (++value).
Note that neither of them are thread-safe.
For added fun, here are two more equivalent options:
value += 1;
value -= -1;
That's incorrect. Rather, ++value is the same as value=value+1.
++Value is a pre-increment. Value++ is a post-increment.
'Post' means after - that is, the increment is done after the variable is read. 'Pre' means before - so the variable value is incremented first, then used in the expression.
For example:
int i, x;
i = 2;
x = ++i;
// now i = 3, x = 3
i = 2;
x = i++;
// now i = 3, x = 2
No, my friend ++value is equivalent to value=value+1 as it is changing the new value preincrement operator
and value++ is changing the old value which is kept in the memory i.e. post incrementing it
I'm doing the oracle certified associate Java SE7 Programmer practice exams (the book) and came across a question, and I don't understand the answer even with the explanation.
Here's the explanation and the code:
It will print 3. The loop body is executed twice and the program will print 3.
I don't understand how the loop body is executed twice, maybe I don't understand what the b=!b means. Can someone explain please?
class TestClass {
public static void main(String args[]){
boolean b = false;
int i = 1;
do{
i + + ;
} while (b = !b);
System.out.println(i);
}
}
b = !b is an assignment which assigns the inverse of b to itself (effectively flipping between true and false)
in java, an assignment returns what was assigned (so that a=b=1 is possible)
therefore while (b=!b) will flip the value of b, and then check the value of b.
b=!b
Will always be true, why?
Because, what you are doing is that you insert to "b" the opposite value (T->F, F->T),and if there was no problem while (b = !b); will return TRUE....
So at your case while (b = !b); will always return true
Iteration 1
boolean b = false;
int i = 1;
do{
i++ ; // i = 2
} while (b = !b); // b = !false = true so one more execution
Iteration 2
do{
i++ ; // i = 3
} while (b = !b); // b = !true = false so loop breaks
So it will print 3. simple :)
Actually the confusion is with = sign. = is assigning operator where as == is the conditional operator. The first will assign the value whereas later will check for the condition. You can play with it and have some other result like
int a = 6;
int b = 10;
System.out.println(a = b);
System.out.println(a == b);
and you will get the idea.
At the end of the first iteration the variable i will be 2 because of the increment operator. The expression b=!b will result to true (b = !false) and set the variable b to true as well. So the loop gets executed again.
At the end of the second iteration the variable i is now 3. The expression b=!b will result to false (b = !true), which will be also the value of the variable b. So the whole do-while-loop terminates and the println() statement shows 3.
Keep in mind: = (assign operator) is not the same as == (equality check).
The condition
b = !b;
uses the assignment operator, which returns the value that has been assigned.
Initially, b is false, and therefore true is assigned to b, and used for the condition. The while loop therefore executes a second time. In this execution, b is true, and therefore false is assigned to b and used for the loop condition. The loop therefore exits.
while( i <= j && i >= j && i != j) {}
how to declare i and j to make it be an infinite loop ?
// it's an interview question I met.
it's asking what's the declarations of i and j, make it be always true.
And I cant make it out by declaring i and j as number types. What other types can meet it ?
Integer i=new Integer(1000);
Integer j=new Integer(1000);
System.out.println((i<=j)+" "+(i>=j)+" "+(i!=j));
i and j will be automatically unboxed to ints for <= and >=, but not for !=. i and j are different instances, but have the same int value. That's why all three comparisons will return true.
This works too ("on my machine"):
Integer a = 128, b = 128;
whereas this won't work:
Integer a = 127, b = 127;
Auto-boxing an int is syntactic sugar for a call to Integer.valueOf(int). This function uses a cache for values from -128 to 127, inclusive. It may cache other values, but in my case, it doesn't.
Thus, the assignment of 128 doesn't have a cache hit; it creates a new Integer instance with each auto-boxing operation, and the reference comparison a != b is true. The assignment of 127 has a cache hit, and the resulting Integer objects are really the same instance from the cache. So, the reference comparison a != b is false.
What I really want to point out is to beware of reference comparison with auto-boxing. A more likely real-world problem is that you expect a == b is true because they were assigned the same (auto-boxed) value, you run some unit tests that confirm your expectation, and then your code fails "in the wild" when some counter exceeds the upper limit of the cache. Fun times!
Any equal value of 'i' and 'j' will reveal true with the given statement, say:
Integer i = new Integer(1);
Integer j = new Integer(1);
while( i <= j && i >= j && i != j) {}
The magic is with used operator! In case of != operator the compiler takes the operands as objects(including their values) whereas in case of >= or <= the compiler takes the operands value only. Thus, the above statement returns true.
I'm a bit confused about the way Java treats == and equals() when it comes to int, Integer and other types of numbers. For example:
Integer X = 9000;
int x = 9000;
Short Y = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
// results.add(X == Y); DOES NOT COMPILE 1)
results.add(Y == 9000); // 2)
results.add(X == y); // 3)
results.add(X.equals(x)); // 4)
results.add(X.equals(Y)); // 5)
results.add(X.equals(y)); // 6)
System.out.println(results);
outputs (maybe you should make your guess first):
[true, true, true, false, false]
That X == Y does not compile is to be expected, being different objects.
I'm a little surprised that Y == 9 is true, given that 9 is by default an int, and given that 1) didn't even compile. Note that you can't put an int into a method expecting a Short, yet here they are equal.
This is surprising for the same reason as two, but it seems worse.
Not surprising, as x is autoboxed to and Integer.
Not surprising, as objects in different classes should not be equal().
What?? X == y is true but X.equals(y) is false? Shouldn't == always be stricter than equals()?
I'd appreciate it if anyone can help me make sense of this. For what reason do == and equals() behave this way?
Edit: I have changed 9 to 9000 to show that this behavior is not related to the any unusual ways that the integers from -128 to 127 behave.
2nd Edit: OK, if you think you understand this stuff, you should consider the following, just to make sure:
Integer X = 9000;
Integer Z = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
results.add(X == Z); // 1)
results.add(X == y); // 2)
results.add(X.equals(Z)); // 3)
results.add(X.equals(y)); // 4)
System.out.println(results);
outputs:
[false, true, true, false]
The reason, as best as I understand it:
Different instance, so different.
X unboxed, then same value, so equal.
Same value, so equal.
y cannot be boxed to an Integer so cannot be equal.
(small) Integer instances are cached, so the invariant x == y is holded for small instances (actually -127 +128, depends on JVM):
Integer a = 10;
Integer b = 10;
assert(a == b); // ok, same instance reused
a = 1024;
b = 1024;
assert(a == b); // fail, not the same instance....
assert(a.equals(b)); // but same _value_
EDIT
4) and 5) yield false because equals check types: X is an Integer whereas Y is a Short. This is the java.lang.Integer#equals method:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
The reason for
X == y
being true has to do with binary numeric promotion. When at least one operand to the equality operator is convertible to a numeric type, the numeric equality operator is used. First, the first operand is unboxed. Then, both operands are converted to int.
While
X.equals(y)
is a normal function call. As has been mentioned, y will be autoboxed to a Short object. Integer.equals always returns false if the argument is not an Integer instance. This can be easily seen by inspecting the implementation.
One could argue that this is a design flaw.
The morale of the story:
Autoboxing/unboxing is confusing, as is type promotion. Together, they make for good riddles but horrendous code.
In practice, it seldom makes sense to use numeric types smaller than int, and I'm almost inclined to configure my eclipse compiler to flag all autoboxing and -unboxing as an error.
Your problem here is not only how it treats == but autoboxing... When you compare Y and 9 you are comparing two primitives that are equal, in the last two cases you get false simply because that's how equals work. Two objects are equal only if they are of the same kind and have the same value.
When you say in "X.equals(y)" you are telling it to do Integer.equals(Short) and looking at the implementation of Integer.equals() it will fail:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Because of autoboxing the last two will result in the same failure as they will both be passed in as Shorts.
Edit: Forgot one thing... In the case of results.add(X == y); it will unbox X and do (X.intValue() == y) which happens to be true as well as 9 == 9
This automatic conversion is called autoboxing.
I remember a good practice for overriding "equal(object obj)" is of first checking the type of the parameter passed in. So perhap this causes X.equals(Y) to be false. You might check the souce code to dig out the truth :)
A bit more detail on how autoboxing works and how "small" valued Integer objects are cached:
When a primitive int is autoboxed into an Integer, the compiler does that by replacing the code with a call to Integer.valueOf(...). So, the following:
Integer a = 10;
is replaced by the compiler with the following:
Integer a = Integer.valueOf(10);
The valueOf(...) method of class Integer maintains a cache that contains Integer objects for all values between -127 and 128. If you call valueOf(...) with a value that's in this range, the method returns a pre-existing object from the cache. If the value is outside the range, it returns a new Integer object initialized with the specified value. (If you want to know exactly how it works, lookup the file src.zip in your JDK installation directory, and look for the source code of class java.lang.Integer in it.)
Now, if you do this:
Integer a = 10;
Integer b = 10;
System.out.println(a == b);
you'll see that true is printed - but not because a and b have the same value, but because a and b are referring to the same Integer object, the object from the cache returned by Integer.valueOf(...).
If you change the values:
Integer a = 200;
Integer b = 200;
System.out.println(a == b);
then false is printed, because 200 is outside the range of the cache, and so a and b refer to two distinct Integer objects.
It's unfortunate that == is used for object equality for value types such as the wrapper classes and String in Java - it's counter-intuitive.
Java will convert an Integer into an int automatically, if needed. Same applies to Short. This feature is called autoboxing and autounboxing. You can read about it here.
It means that when you run the code:
int a = 5;
Integer b = a;
System.out.println(a == b);
Java converts it into:
int a = 5;
Integer b = new Integer(a);
System.out.println(a == b.valueOf());