List<Integer> stack1 = new ArrayList<>();
List<Integer> stack2 = new ArrayList<>();
//some add operation
......
//some add operation
if(stack1.remove(index1) == stack2.get(index2-1))
stack2.remove(--index2);
The code above works wrong.
While the code below works right.
List<Integer> stack1 = new ArrayList<>();
List<Integer> stack2 = new ArrayList<>();
//some add operation
......
//some add operation
int i = stack1.remove(index1);
int j = stack2.get(index2-1);
if(i == j)
stack2.remove(--index2);
The former code works that even if the 'if' sentence in latter code judges true, it judges false, which makes me confused.
The stack elements are Integer objects. In the first case you compare them for identity, in the second case you compare the values.
Try this
if(stack1.remove(index1).equals(stack2.get(index2-1)))
In Java, the == comparator on Object references don't test that the values of the Objects are equivalent. It tests that the references refer to the same Object. In the first case, you're checking if the Integer reference from stack1 and Integer reference from stack2 both refer to the same Integer object.
To test Objects for value equivalence, you generally use the object.equals(otherObject) method.
In the second case, Java does a sneaky thing called autoboxing where it converts an Object to its primitive type, i.e. from Integer to int. The == comparison on primitives is what you'd expect.
See https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html from more info on autoboxing.
In the first case you're using the '==' operator on two Integer objects. That check evaluates to 'true' only if the the two object references point to the same object (same memory location). In the second case you're using '==' operator on two primitive integers. That check evaluates to true if the value of the primitives is the same, even if they reside in different memory locations.
Related
import java.util.Stack;
public class StackIntro {
public static void main(String[] args){
Stack clapper = new Stack();
for( int i=0; i<11; i++){
clapper.push(i);
}
while(!clapper.isEmpty()){
System.out.print ( clapper.pop() ); //FILO
System.out.print ( ',' );
if(clapper.size()==1){
System.out.print(clapper.pop()); //FILO
System.out.println("...");
}
}
System.out.println("Lift-off.");
clapper.removeAllElements();
}
}
So basically I just wanted to see how numbers go in and out of a stack. The FILO comment shows this. I was told that I should actually change line 8 :
clapper.push(i); //previous
clapper.push(new Integer(i)); //new
I don't understand what this would accomplish, or the difference between the two.
Although due to autoboxing both lines of code result in an Integer object with value 1 being pushed on the stack, the two lines do not have exctly the same effect.
Autoboxing uses the Integer cache, which is required by the JLS for values from -128 to 127, such that the resulting Integer instance is the same instance for any value in that range.
However, invoking the int constructor creates a new Integer instance every time it's called.
Consider:
Integer a = 1; // autoboxing
Integer b = 1; // autoboxing
System.out.println(a == b); // true
Integer c = new Integer(1);
Integer d = new Integer(1);
System.out.println(c == d); // false
This distinction may cause different behaviour in your program if you use == (object identity) when comparing values pushed and popped to/from the stack instead of equals().
This would not accomplish much, very possibly not anything at all.
The idea is that clapper.push(T) accepts an object, but i is not an object, it is a primitive, so the compiler will automatically box it into an Integer object before passing it to clapper.push().
Auto-boxing was not a feature of java from the beginning, so there may still exist some old-timers who are uncomfortable with it. But that should be entirely their own problem. Java has come a long way since then. Auto-boxing is taken for granted, we do not even give it any thought anymore.
Passing i and having the compiler auto-box it is exactly the same as as passing new Integer(i).
I have written following code
class Test {
public static void main(String... args) throws Exception{
Set<Integer> s = new HashSet();
Integer i1 = new Integer(1);
s.add(i1);
Integer i2 = new Integer(2);
s.add(i2);
i1 = 5;
s.remove(i1);
System.out.println("size= "+s.size());
}
}
Output: 2
I have added two integers(i1 and i2) in set and i1 is modified.
When s.remove(i1) is there, output is 2
when I comment out s.remove(i1) still output is 2.
Why this is so.How it is working in background.
Thnaks in advance!
Integer objects are immutable objects and hence any change to them will create a new object. So when you change
i1 = 5;
the original i1 which was stored in set is not changed. As i1 now holds the reference of a different object, which is not present in Set so calling
s.remove(i1);
will have no effect i.e. it does not remove anything and the size of the set remains 2. To confirm whether remove has removed anything or not, you can use boolean return value of remove method. It will return true if the value is removed. So try this:
if(s.remove(i1)) {
System.out.println("i1 removed");
} else {
System.out.println("i1 NOT removed");
}
This line
i1 = 5;
is actually compiled to
i1 = Integer.valueOf(5);
So after execution, i1 is holding another (new) reference, with a value that is not in the HashSet, so nothing is removed.
Java primitives types can only have VALUES.
While Java boxed types have VALUE and IDENTITY.
Two Java boxed types can have same VALUE but different IDENTITY.
Java boxed types are IMMUTABLE; any change in their VALUE will also change the IDENTITY.
If IDENTITY of an object is changed; Java collections cant work effectively.
Statement: i1 = 5; => is actually i1 = Integer.ValueOf(5) => which meant new VALUE of i1.
Collections store only IDENTITY but not VALUE.
Removal by non existing IDENTITY (i1 = 5) from collection, will result nothing.
Source ..... Effective Java by Joshua Bloch
Collections (Set is a collection) in java works with the 'equals()' method, not with the '=' reference operator. That is, when you set 'i1=5', and then 's.remove(i1)', the remove method will compare with all elements.
a) Beginning with the first: is 5 equal to 1?. No, so don't remove that element.
b) The second: is 5 equal to 2?. No, so don't remove that element.
Adding duplicate works the same, on an empty set:
i1=1;
i2=1;
s.add(i1);
s.add(i2)
This will result on a set with only 1 element, because 'i1.equals(i2)' is true, and doesn't matter that 'i1=i2' is NOT true.
It is very important to distinguish between objects and reference variables. A reference expression, including a reference variable, is either null or a pointer to some object.
The HashSet contains its own pointers to the objects in the set it represents. Working through the code:
Set<Integer> s = new HashSet();
// s is a pointer to a new, empty, HashSet.
Integer i1 = new Integer(1);
// i2 is a pointer to an Integer object with value 1
s.add(i1);
// The set contains one Integer object, value 1
Integer i2 = new Integer(2);
s.add(i2);
// The set contains two Integer objects, values 1 and 2
i1 = 5;
// i1 is a pointer to an Integer object with value 5
s.remove(i1);
// The set does not contain any object that is equal
// to an Integer with value 5 so it is unchanged
Becase after you do "i1 = 5;", i1 starts pointing to another address. And it is no more the same Integer than is stored in your HashSet.
I know the concept of String pool in PermGen area of heap. So when we do something like
String firstString = "Stack";
String secondString = "Stack";
both references firstString and secondString point to the same object in the pool. But I tried the same for a variable of type int.
int firstInt = 5;
int secondInt = 5;
if(firstInt == secondInt) {
System.out.println("Both point to same allocated memory");
} else {
System.out.println("Both point to different allocated memory");
}
and the result is Both point to same object and when i tried
Integer firstInteger = new Integer(2);
Integer secondInteger = new Integer(2);
if(firstInteger == secondInteger) {
System.out.println("Both point to same object");
} else {
System.out.println("Both point to different object");
}
output is Both point to different object
I tried the same for char and the result is similar. So my question do we have pools for all primitive types like int, char? And when we actually create objects with same content using new () as in the second case mentioned above is the object cloned and stored in same pool area or is it outside the pool?
There is so much misconception in your post, it is hard even to start explaining. Get some decent book. For now, some facts that might help you:
String is not a primitive type,
there are no pools of primitive types, because there cannot be a reference to a primitive type (the answer saying that they are only kept on the stack is plain wrong!)
if you use new, you bypass pools anyway; so executing new String("ala") will always create a new String object; you cannot change the semantics of new;
if you want to use available pools, use factory methods on objects (like Integer.valueOf), they will - to some extent - pool instances (it is not viable or beneficial to pool all possible values of Integers, Floats etc.).
Primitives are not objects. They can be stored directly in the generated code.
In your second code block, you're testing equality of value, not that two objects are the same.
int firstInt = 5;
int secondInt = 5;
if(firstInt == secondInt)
{
System.out.println("Both point to same object");
// NO - neither point to an object -- their alues are the same.
}
You can share the same Integer object among multiple references by explicitly using Integer.valueOf(int), which may return the same object for multiple calls.
If you try
if (Integer.valueOf(2) ==Integer.valueOf(2))
you will get true.
With the Integer firstInt = new Integer(2) you create a new local variable that is != to another local variable created with Integer secondInt = new Integer(2). Same goes for String type.
The reason behind this is that == checks equality of the variables. Variables could be different (== results in false) even though they point to two objects that are "the same". The same in this context means obj1.equals(obj2) returns true.
If you want object representation of primitve types and also StringS to be stored in PermGen then do not use new keyword, i.e. Integer firstInt = 2;, String firstString= "whatevs"; beacause the keyword new creates an object on the heap.
Sometimes, to answer advanced questions it is enough to look through source code. For instance, here is the code of Integer#valueOf(int i) method:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Values IntegerCache#low and IntegerCache#high could be changed via vm options:
The size of the cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.
I believe this is a very valid question that needs to be answered. For any future readers, the way the == operation works for Object types and primitive types are different.
Primitive types(int, char, double, long....) are evaluated by their values.
Whereas Primitive Wrappers (Integer, Double, String ....) are actually objects and not just values.
So when we use Integer class as
Integer number = new Integer(10)
A new Object is created in the memory which is not the case for primitive data types.
The == evaluation checks the memory, as well as the value for the Object types and for primitive types, checks the value only.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Difference Between Equals and ==
For example, if I have
MyClass foo = new MyClass();
MyClass bar = new MyClass();
if (foo == bar) {
// do something
}
if (foo < bar) {
// do something
}
if (foo > bar) {
// do something
}
how do foo and bar get compared? Does Java look for .compareTo() methods to be implemented for MyClass? Does Java compare the actual binary structure of the objects bit for bit in memory?
Very simply the arithmetic comparison operators == and != compare the object references, or memory addresses of the objects. >, and < and related operators can't be used with objects.
So ==, != is useful only if you want to determine whether two different variables point to the same object.
As an example, this is useful in an event handler: if you have one event handler tied to e.g. multiple buttons, you'll need to determine in the handler which button has been pressed. In this case, you can use ==.
Object comparison of the type that you're asking about is captured using methods like .equals, or special purpose methods like String.compareTo.
It's worth noting that the default Object.equals method is equivalent to ==: it compares object references; this is covered in the docs. Most classes built into Java override equals with their own implementation: for example, String overrides equals to compare the characters one at a time. To get a more specific/useful implementation of .equals for your own objects, you'll need to override .equals with a more specific implementation.
You didn't try it yourself, apparently, because <, >, <= and >= do not work on Objects.
However, == compares the left and right operand. When they are binary the same, it results in true. In the case of objects, in compares the pointers. So which means that this will only result in true if the Object is left and right the very same object in memory.
Other methods, like compareTo and equals are made to provide a custom method of comparing to different objects in memory, but which might be equal to each other (i.e. the data is the same).
In case of Strings, for example:
String str0 = new String("foo");
String str1 = new String("foo");
// A human being would say that the two strings are equal, which is true
// But it are TWO different objects in memory. So, using == will result
// in false
System.out.println(str0 == str1); // false
// But if we want to check the content of the string, we can use the equals method,
// because that method compares character by character of the two objects
String.out.println(str0.equals(str1)); // true
String.out.println(str1.equals(str0)); // true
No it doesn't. It compares whether the two variables are references to the same objects.
Unless you're dealing with types which are subject to autoboxing, such as Integer, you can't use > and < with objects at all.
In the case where you are using an autoboxed type, java doesn't look for specific methods, but will auto-unbox the variables, turning them into primitives - but this isn't the case for the equals operator. The == operator will always compare objects as references, even when comparing autoboxed objects:
Integer i1 = new Integer(10);
Integer i2 = new Integer(10);
if(i1 < i2) { // evaluates to false!
System.out.println("i1 is less than i2");
}
else if(i1 > i2) { // evaluates to false!
System.out.println("i1 is greater than i2");
}
else if(i1 == i2) { // evaluates to false!
System.out.println("i1 and i2 are equal");
}
else {
System.out.println("Um... well that's just confusingi");
}
It compares the reference value and will only return true if foo and bar point to the same object.
In Java, "==" compares the object identity. "new" is guaranteed to return a new object identity each time.
I'd actually love if "==" would call compareTo. Alas, it doesn't.
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.