Autoboxing in Java

Autoboxing in Java

Autoboxing in Java means the ability to convert primitive types like int, float etc to primitive primitive wrapper classes such as Integer, Float etc. The below syntax helps to show, how to converts int into Integer class. There are multiple examples here which helps to learn about boxing and unboxing. The advantages and disadvantages are also covered.

Syntax: –

int inative = 0;
inative = new Integer(5); // auto-unboxing
Integer intObject = 5; // autoboxing
The autoboxing mechanism also supports comparison operation.
Syntax: - int a = 10;
Integer b = 10;
System.out.println(a==b);

Example: –

public static void main(String[] args)
{
Map<String, Integer> map = new HashMap<String, Integer>();
// Here we put an int into the Map, and it accepted
// as it will be autoboxed or converted into the wrapper
// of this type, in this case the Integer object.
map.put(“Age”, 25);
// Here we can just get the value from the map, no need
// to cast it from Integer to int.
int age = map.get(“Age”);
// Here we simply do the math on the primitive type
// and got the result as an Integer.
Integer newAge = age + 10;
}

New to Java 5 is a feature known variously as: autoboxing, auto-unboxing, boxing, and unboxing. We’ll stick with the terms boxing and unboxing. Boxing and unboxing make using wrapper classes more convenient. In the old, pre–Java 5 days, if you wanted to make a wrapper, unwrap it, use it, and then rewrap it, you might do something like this:

Integer y = new Integer(567); // make it
int x = y.intValue(); // unwrap it
x++; // use it
y = new Integer(x); // re-wrap it
System.out.println(“y = “ + y); // print it
Now, with new and improved Java 5 you can say
Integer y = new Integer(567); // make it
y++; // unwrap it, increment it,
// rewrap it
System.out.println(“y = “ + y); // print it
Both examples produce the output:
y = 568

The code appears to be using the post increment operator on an object reference variable! But it’s simply a convenience. Behind the scenes, the compiler does the unboxing and reassignment for you. Earlier we mentioned that wrapper objects are immutable, this example appears to contradict that statement. It sure looks like y’s value changed from 567 to 568. What actually happened, is that a second wrapper object was created and its value was set to 568. If only we could access that first wrapper object, we could prove it,

Integer y = 567; // make a wrapper
Integer x = y; // assign a second ref
// var to THE wrapper
System.out.println(y==x); // verify that they refer
// to the same object
y++; // unwrap, use, “rewrap”
System.out.println(x + “ “ + y); // print values
System.out.println(y==x); // verify that they refer
// to different objects

Which produces the output:-

true

567 568

false

So, under the covers, when the compiler got to the line y++; it had to substitute something like this:

int x2 = y.intValue(); // unwrap it
x2++; // use it
y = new Integer(x2); // re-wrap it

Just as we suspected, there’s gotta be a call to new in there somewhere.

 

Boxing, ==, and equals()

We just used == to do a little exploration of wrappers. Let’s take a more thorough look at how wrappers work with ==, !=, and equals(). For now all we have to know is that the intention of the equals() method is to determine whether two instances of a given class are “meaningfully equivalent.” This definition is intentionally subjective; it’s up to the creator of the class to determine what “equivalent” means for objects of the class in question. The API developers decided that for all the wrapper classes, two objects are equal if they are of the same type and have the same value. It shouldn’t be surprising that

Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2) System.out.println(“different objects”);
if(i1.equals(i2)) System.out.println(“meaningfully equal”);

Produces the output:

different objects

meaningfully equal

It’s just two wrapper objects that happen to have the same value. Because they have the same int value, the equals() method considers them to be “meaningfully equivalent”, and therefore returns true. How about this one:

Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4) System.out.println(“same object”);
if(i3.equals(i4)) System.out.println(“meaningfully equal”);

This example produces the output:

same object

meaningfully equal

The equals() method seems to be working, but what happened with == and != ? Why is != telling us that i1 and i2 are different objects, when == is saying that i3 and i4 are the same object? In order to save memory, two instances of the following wrapper objects (created through boxing), will always be == when their primitive values are the same:

  • Boolean
  • Byte
  • Character from \u0000 to \u007f (7f is 127 in decimal)
  • Short and Integer from -128 to 127

When == is used to compare a primitive to a wrapper, the wrapper will be unwrapped and the comparison will be primitive to primitive.

Where Boxing Can Be Used

It’s very common to use wrappers in conjunction with collections. Any time you want your collection to hold objects and primitives, you’ll want to use wrappers to make those primitives collection-compatible. The general rule is that boxing and unboxing work wherever you can normally use a primitive or a wrapped object. The following code demonstrates some legal ways to use boxing:

class UseBoxing {
public static void main(String [] args) {
UseBoxing u = new UseBoxing();
u.go(5);
}
boolean go(Integer i) { // boxes the int it was passed
Boolean ifSo = true; // boxes the literal
Short s = 300; // boxes the primitive
if(ifSo) { // unboxing
System.out.println(++s); // unboxes, increments, reboxes
}
return !ifSo; // unboxes, returns the inverse
}
}

Advantages of autoboxing

  1. Less code to write: – The code looks cleaner.
  2. The best method for conversion is automatically chosen, e.g. Integer.valueOf(int) is used instead of new Integer(int)

Disadvantages of autoboxing

1)      It can lead to unexpected behavior: – The usage of autoboxing can lead to difficult to recognize errors. If you mix wrapper with primitives in ‘equals’/’==‘.

Eg: – Long l = 0L;

System.out.println(l.equals(0L));

System.out.println(l.equals(0));

2)      Hiding: – Hiding of the object creation leads to big performance loss.

Example: –

Integer counter = 0;
for(int i=0; i < 1000; i++) {
counter++;
}

3)      Overloading:-

Example: –

public static void main(String[] args) throws Exception
{
Integer l = 0;
fubar(l);
}
static void fubar(long b) {
System.out.println(“1”);
}
static void fubar(Long b) {
System.out.println(“2”);
}

The below example helps to compare wrappers and primitive comparison:-

public class WrappersTest {
public static void main(String[] s) {
Integer i1 = new Integer(2);
Integer i2 = new Integer(2);
System.out.println(i1 == i2); // FALSE
Integer j1 = 2;
Integer j2 = 2;
System.out.println(j1 == j2); // TRUE
Integer k1 = 150;
Integer k2 = 150;
System.out.println(k1 == k2); // FALSE
Integer jj1 = 127;
Integer jj2 = 127;
System.out.println(jj1 == jj2); // TRUE
int jjj1 = 127;
Integer jjj2 = 127;
System.out.println(jjj1 == jjj2); // TRUE
Integer kk1 = 128;
Integer kk2 = 128;
System.out.println(kk1 == kk2); // FALSE
Integer kkk1 = 128;
int kkk2 = 128;
System.out.println(kkk1 == kkk2); // TRUE
Integer w1 = -128;
Integer w2 = -128;
System.out.println(w1 == w2); // TRUE
Integer m1 = -129;
Integer m2 = -129;
System.out.println(m1 == m2); // FALSE
int mm1 = -129;
Integer mm2 = -129;
System.out.println(mm1 == mm2); // TRUE
}
}