Engineering Full Stack Apps with Java and JavaScript
The wrapper classes provide a mechanism to "wrap" primitive values in an object so that the primitives can be included in activities only for objects, like being added to Collections. There is a wrapper class for every primitive in Java. The wrapper class for int is Integer and the class for float is Float and so on. Wrapper classes also provide many utility functions for primitives like Integer.parseInt().
Use case: Write a method which can accept anything. You can write the method as public method(Object obj){}. Now since all classes are children of Object class, their objects can be passed. However primitive types are not children of Object and hence cannot be passed. We can wrap the primitives inside corresponding wrapper classes and then pass to the function.
1. Using constructor as
Integer i1 = new Integer(42);
All of the wrapper classes except Character provide two constructors: one that takes a primitive type and one that takes a String representation of the primitive type: new Integer(42) or new Integer("42"). The Character class provides only one constructor, which takes a char as an argument: new Character('c').
2. Using valueOf() as
Float f2 = Float.valueOf("3.14f");
3. Directly assigning a primitive to a wrapper reference, in which case java will automatically create an object for you, which is called as Autoboxing as
Long weight = 1200L;
There are many utility functions for the wrapper class, mainly for conversions like:
double d4 = Double.parseDouble("3.14");
Double d5 = Double.valueOf("3.14");
From Java 5, Java does the conversion of primitive to wrapper and wrapper to primitive automatically. When you use a primitive in the context of a wrapper class, java will automatically convert (or wrap or box) the primitive into the wrapper class, which is called auto-boxing. When you use a wrapper class in the context of a primitive, java will automatically convert (or unwrap or unbox) the wrapper into the primitive, which is called auto-unboxing.
Consider an example without auto-boxing:
Integer y = new Integer(567);
int x = y.intValue();
x++;
y = new Integer(x);
System.out.println("y = " + y);
Same example above with auto-boxing:
Integer y = new Integer(567);
y++; // unbox (unwrap), increment it, box (rewrap)
System.out.println("y = " + y);
Consider another example of a method method1 that accepts an Integer wrapper and returns an integer value:
public int method1(Integer i){return i;}
When you invoke the method as int j = method1(5); Java wrap the primitive 5 as an Integer wrapper object and pass to the method and then inside the method it unwrap Integer i and return as a integer. Note that within method1, you can call any utility method on I, which would not have been possible without boxing.
Note that wrapper reference variables can be null. Doing auto-unboxing on them might result in a NullPointerException.
The == checks whether two objects are actually equal, i.e. whether they actually refer to the same object in memory. The equals() method checks whether two objects are meaningfully equal, for example, it checks whether two wrappers or strings are having the same value.
The == actually checks whether two variables are having exactly same value. Note that a primitive variable contain what you see, but a reference variable contain the address to the object that it holds. When == is used to compare a primitive to a wrapper, the wrapper will be unwrapped and the comparison will be primitive to primitive, and hence it will be true always as it is a primitive comparison and not object comparison.
In order to save memory, two instances of the following wrapper objects (created through boxing), will always be equal (==) when their primitive values are the same:
For example, System.out.println(i1 == i2); will print true when i1 and i2 are having same value between -128 to 127 and will print false if i1 and i2 are outside -128 to 127 range even though both are same. This is similar to string pool concept, but with a range limit in certain cases.
Question 1:
Find the output:
Integer i1 = 1000; Integer i2 = 1000;
Integer i3 = 10; Integer i4 = 10;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
Question 2:
Find the output:
Integer x = 400;
Integer y = x;
x++;
System.out.println((x==y) ;
Question 3
Find the output:
Integer x = 400;
Integer y = x;
x++; x--;
System.out.println((x==y) ;
Question 4
Find the output:
Integer x = 100;
Integer y = x;
x++; x--;
System.out.println((x==y) ;
Answer 1
This will print false and true.
Answer 2
This will print false. Initially both x and y are refering to the same object, but then x is incremented which will auto-unbox x to integer 400, does the addition and box it in another wrapper instance and assign to x. So x and y are completely different objects now.
Answer 3
It will print false. Here we are incrementing and decrementing immediately. So first java will do autounboxing, increment x and through autoboxing it wraps it in another object. Then for x--, it again will do autounboxing, decrement x and through autoboxing it wraps it in another object. This is also a new object created by java and hence not same as old one.
Answer 4
It will print true. When we assign 100 to x , or any number between -128 and 127, java will not create a different wrapper object but reuse the existing one. First, for x++, java will do autounboxing, increment x and through autoboxing it wraps it in another object. However in the second step, x--, it does the decrement and when creating a object it sees that there is already another object within the range -128 to 127 with the same value, decides to reuse that object and assign that to x. So x and y are same again and will print true.