Autoboxing and unboxing in java - How it works internally in detail with 10 examples- Widening, AutoBoxing and Var-args


In this core java tutorial we will learn in depth about Autoboxing and Unboxing with programs and examples. How Autoboxing and unboxing works internally in java. We will take this topic to compiler level for deep and perfect understanding of Autoboxing and Unboxing in java.



Contents of page -
  • What is Autoboxing in java
  • What is Unboxing in java
  • Autoboxing and Unboxing were introduced in which java version?
  • Who is responsible for performing Autoboxing and unboxing in java?
  • Now, let’s discuss 10 examples to understand Autoboxing and Unboxing in detail >
    • Program / Example 1 - Autoboxing Example 1 in java >
    • Program / Example 2 - Unboxing Example 1 in java >
    • Program / Example 3 - Autoboxing Example 2 in java >
    • Program / Example 4 - Unboxing Example 2 in java >
    • Program / Example 5 - Where Autoboxing and Unboxing will be performed in below program in java ?
    • Program / Example 6 - If Integer has to added to Integer than first both will be converted to int in java >
    • Comparing primitive type and corresponding wrapper class using == (Example 7 - 10) in java>
    • Example 9 and Example 10 are very important examples in java.
    • Program / Example 9 - compare Integer with Integer (where both Integers are formed without using new operator) using == operator for comparison >
    • Program / Example 10 -  compare new Integer with new Integer using == operator for comparison >
  • Be careful while using wrapper classes in java >
  • Table to represent Primitive data type and their Corresponding Wrapper class  in java>
  • Advantage of using primitive data types (Avoid boxing and unboxing) in java >
  • Advantage of using Object wrapper class in java >
  • We may set up our eclipse to find out when boxing or unboxing is done in java >
  • Method overloading in java with
  1. Widening - We discussed a lot about widening in Program 5.2 and 5.3
  2. Autoboxing
  3. Var-args


What is Autoboxing in java
Autoboxing is the automatic conversion of primitive data type to corresponding wrapper class.
Example - converting  int to Integer, byte to Byte etc.

What is Unboxing in java
Unboxing is vice-versa of Autoboxing. Unboxing is the automatic conversion of wrapper class to corresponding primitive data type.
Example - converting  Integer to int , Byte to byte etc.

Autoboxing and Unboxing were introduced in which java version?
Autoboxing and Unboxing were introduced in java 5 just after C# introduced it. Before java 5 manual code was written to convert int to Integer or vice-versa.

Who is responsible for performing Autoboxing and unboxing in java?
Java compiler is responsible for making such conversions.


Now, let’s discuss 10 examples to understand Autoboxing and Unboxing in detail >
Program / Example 1 - Autoboxing Example 1 in java >
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
         
          int i = 12;
          Integer iObject = i; // Autoboxing
   }
}

Java compiler will convert above code into -
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
         
          int i = 12;
          Integer iObject = Integer.valueOf(i); // This is Autoboxing
   }
}
Before java 5 we used to write such code for performing Autoboxing.

But now see how compiler performs Autoboxing internally >
Go to CMD and type javap -c Autoboxing.class command
C:\workspace> javap -c Autoboxing.class
public class Autoboxing {
 public boxing_unboxing_1.Autoboxing();
   Code:
      0: aload_0
      1: invokespecial #8                  // Method java/lang/Object."<init>":()V
      4: return

 public static void main(java.lang.String[]);
   Code:
      0: bipush        12
      2: istore_1
      3: iload_1
      4: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      7: astore_2
      8: return
}




Program / Example 2 - Unboxing Example 1 in java >
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Unboxing{
   public static void main(String[] args) {
         
          Integer iObject = 12;
          int i = iObject; // Unboxing
   }
}

Java compiler will convert above code into -
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Unboxing{
   public static void main(String[] args) {
         
          Integer iObject = Integer.valueOf(12); // equivalent to >  Integer iObject = 12;  
          int i = iObject.intValue(); // This is Unboxing
   }
}
Before java 5 we used to write such code for performing Unboxing.


But now see how compiler performs Unboxing internally >
Go to CMD and type javap -c Unboxing.class command
C:\workspace> javap -c Unboxing.class
public class Unboxing {
 public boxingUnboxing_1.Unboxing();
   Code:
      0: aload_0
      1: invokespecial #8                  // Method java/lang/Object."<init>":()V
      4: return

 public static void main(java.lang.String[]);
   Code:
      0: bipush        12
      2: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      5: astore_1
      6: aload_1
      7: invokevirtual #22                 // Method java/lang/Integer.intValue:()I
     10: istore_2
     11: return
}





Program / Example 3 - Autoboxing Example 2 in java >
import java.util.ArrayList;
import java.util.List;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
          List<Integer> arrayList = new ArrayList<Integer>();
          for (int i = 0; i < 3; i ++){
                 arrayList.add(i); //Autoboxing will be performed
                                            //(int is autoboxed to Integer by compiler)
          }
   }
}

List is generic type and it allows to add Integer objects only.
But then how we are able to add int datatype in that list? why compiler didn't threw compilation error?
Because at runtime int is autoboxed to Integer by compiler.
[ primitive data type (i.e. int) is converted  to corresponding wrapperClass(i.e. Integer) ]

Java compiler will convert above code into -
import java.util.ArrayList;
import java.util.List;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
          List<Integer> arrayList = new ArrayList<Integer>();
          for (int i = 0; i < 3; i ++)
                 arrayList.add(Integer.valueOf(i)); //This is Autoboxing
   }
}



Program / Example 4 - Unboxing Example 2 in java >
import java.util.ArrayList;
import java.util.List;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Unboxing{
   public static void main(String[] args) {
         
          List<Integer> arrayList = new ArrayList<Integer>();
          for (int i = 0; i < 3; i ++)
                 arrayList.add(i);
         
          int sum = 0;
          for(Integer n : arrayList){
                 sum += n; //Unboxing will be performed
                           //(Integer is unboxed to int by compiler)
          }
         
   }
}

In above program we are adding Integer to int.
But how we are able to add Integer to int datatype? why compiler didn't threw compilation error?
Because at runtime Integer is unboxed to int by compiler.
[ wrapperClass(i.e. Integer) is converted  to corresponding primitive data type (i.e. int) ]

Java compiler will convert above code into -
import java.util.ArrayList;
import java.util.List;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Unboxing{
   public static void main(String[] args) {
         
          List<Integer> arrayList = new ArrayList<Integer>();
          for (int i = 0; i < 3; i ++)
                 arrayList.add(i);
         
          int sum = 0;
          for(Integer n : arrayList){
                 sum += n.intValue() ; //This is Unboxing
          }
         
   }
}




Program / Example 5 - Where Autoboxing and Unboxing will be performed in below program in java ?
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class AutoboxingUnboxing{
   public static void main(String[] args) {
          Integer sum = 0;
          for (int i = 0; i < 3; i++) {
                 sum = sum + i;
          }
   }
}

Boxing and Unboxing both will be performed in below code.

Java compiler will convert above code into -
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class AutoboxingUnboxing{
   public static void main(String[] args) {
          Integer sum = Integer.valueOf(0);
         
          for (int i = 0; i < 3; i++) {
                
                 //First sum is unboxed to int [sum.intValue()]
                 //than sum is added to i   [sum.intValue() + i], internally int is added to int
                 //than result in Autoboxed to Integer and assigned to sum.
                 sum = Integer.valueOf((sum.intValue() + i));
         
          }
   }
}


But now see how compiler performs Autoboxing and Unboxing internally >
Go to CMD and type javap -c AutoboxingUnboxing.class command
C:\workspace> javap -c AutoboxingUnboxing.class


Note : Logic to memorize above conversions is that internally always int is added to int.
One more example - If Integer has to added to Integer than first both will be converted to int (As shown in Example 6)

Program / Example 6 - If Integer has to added to Integer than first both will be converted to int in java >
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = 4;
          Integer i2 = 5;
          Integer i3 = i1 + i2;
   }
}

In above program we are adding Integer to Integer.
  • First both Integers will be unboxed to int,
  • then both ints are added and result is int
  • Ultimate result (i.e. int) is autoboxed to Integer.

Java compiler will convert above code into -
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = Integer.valueOf(4);
          Integer i2 = Integer.valueOf(5);
          Integer i3 = Integer.valueOf( i1.intValue() + i2.intValue() );
   }
}




Comparing primitive type and corresponding wrapper class using == (Example 7 - 10) in java>
The == operator checks for referential equality of object, it checks whether two references are referring to same object or not.

Program / Example 7 - compare int with int and == operator for comparison in java >
public class Autoboxing{
   public static void main(String[] args) {
          int i1 = 3;
          int i2 = 3;
          System.out.println(i1 == i2); //true
   }
}
/*output
true
*/

int is compared with int.

Java compiler will convert above code into -
No conversions will be made by java compiler



Program / Example 8 - compare int with Integer using == operator for comparison in java >
public class Autoboxing{
   public static void main(String[] args) {
          int i1 = 3;
          Integer i2 = 3;
          System.out.println(i1 == i2); //true
   }
}
/*output
true
*/

3 is autoboxed to Integer and assigned to Integer i2.
And during comparison, Integer i2 is unboxed to int and then compared with int i1, hence 3=3 returns true.

Java compiler will convert above code into -
public class Autoboxing{
   public static void main(String[] args) {
          int i1 = 3;
          Integer i2 = Integer.valueOf(3);
          System.out.println(i1 == i2.intValue()); //true
   }
}


Example 9 and Example 10 are very important examples in java.

I AM HIGHLIGHTING THESE VERY IMPORTANT EXAMPLES.

Program / Example 9 - compare Integer with Integer (where both Integers are formed without using new operator) using == operator for comparison >
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = 3; //caches Integer object
          Integer i2 = 3; //returns cached Integer object
          System.out.println(i1 == i2); //true
   }
}
/*output
true
*/

Java caching >
Java caches all the Integer objects formed from primitive int values between values -128 to 127 (including -128 and 127). This caching is done in Integer.valueOf method. Hence, Integer.valueOf method returns cached object(if any) for primitive int values between values -128 to 127.  
Note : 127 is just the default value, it’s not the fixed value it can be changed.



Why java do such caching?
  • Java caches the Integer object of most frequently used int values.
  • For optimizing performance.
  • For reducing number of objects formed in heap.

Many java experts have criticized this caching process because it enforces kind of different mechanism for different int values (i.e. for int values not in range of -128 to 127). Example -
Integer i1= 150; //no caching, hence 1st Integer object is formed
Integer i2= 150; //no caching was done, hence 2nd Integer object is formed
When any primitive int value like 150 is used no caching is performed and two Integer objects are formed.


Now, in the above program,
Integer i1 = 3;
3 is autoboxed to Integer (new Integer object is formed) in Integer.valueOf(3) method, new Integer object is cached (as 3 is between -128 to 127) and is referred by Integer i1.

Integer i2 = 3;
Integer.valueOf(3) method returns cached object and now same Integer object is being referred by Integer i1 and i2.
Hence, only one Integer object will be formed in above program.

Java compiler will convert above code into -
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = Integer.valueOf(3); //caches Integer object
          Integer i2 = Integer.valueOf(3); //returns cached Integer object
          System.out.println(i1 == i2); //true
   }
}



Program / Example 10 -  compare new Integer with new Integer using == operator for comparison >
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = new Integer(3);
          Integer i2 = new Integer(3);
          System.out.println(i1 == i2); //false
   }
}
/*output
false
*/

Whenever new operator is used new objects are formed.
As we know, the == operator checks for referential equality of object, it checks whether two references are referring to same object or not, i1 == i2 will always return false.
We must prefer to use equals method for comparing Integer objects i1 and i2 (because Integer class overrides equals method and checks for value rather than referential equality) i1.equals(i2) will return true.
public class Autoboxing_EqualsMethod{
   public static void main(String[] args) {
          Integer i1 = new Integer(3);
          Integer i2 = new Integer(3);
          System.out.println(i1.equals(i2)); // true
   }
}
/*output
true
*/


Be careful while using wrapper classes in java >
We must use wrapper classes cautiously because unnecessary usage of wrapper classes might result in formation of unnecessary objects and wastage of heap space in memory.

Table to represent Primitive data type and their Corresponding Wrapper class  in java>
Primitive data type
Corresponding Wrapper class
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
boolean
Boolean
char
Character




Advantage of using primitive data types (Avoid boxing and unboxing) in java >

1) Let's start with example where we will add two numbers using int and Integer-

For addition of two numbers we must prefer to use primitive data type, not the Object wrapper class.
Addition of two numbers using Integers turns out into very costly operation in terms of performance, boxing/unboxing and unnecessary object formations.
Just imagine a situation where 1000000’s... of number are being added using Integer, it will literally explode our heap memory and boxing/unboxing operations will have adverse effect on performance.


2) Object formation, memory constraint and garbage collection -
As explained in above example if possible use primitive types -
  • if you care about object formation in heap,
  • if you have memory constraint and
  • if you care about garbage collector’s performance.


3) Performance -
primitive types give better performance as compared to Objects because in that case no autoboxing/ unboxing is performed.(As explained in the above example)



4) Using primitive in applications -
We must use prefer to use primitive data types where lots of calculations have to performed. Example - Calculator application.


5) int and Integer in for loop >
Executing simple for loop using Integer turns into very costly operation in terms of performance, boxing/unboxing and unnecessary object formations.


6) Let’s compare performance when int and Integer are used in for loop >
When int is used in for loop program completed in 3 milliSeconds
but, when Integer is used in for loop program completed in 4928 milliSeconds.

performance of for loop with Integer degraded significantly because of -
  • unnecessary Integer objects formation in heap
  • Frequent execution of garbage collection processes.
    • unnecessary autoboxing/ unboxing operations.

Note : Performance may vary upon different machines.



Advantage of using Object wrapper class in java >
7) Initializing object wrapper class to null -
Using Objects can be handy at times because they can be initialized to null.
But primitive data types are always initialized to some default value. Example - int is initialized with 0, it can never be null.
Let’s take an example where initialization of int to 0 may be misleading. In an organization employee id or some other identification code being 0 may create numerous confusion to other developers.
Initializing Integer Object to null be very handy over there, it won’t be misleading neither it would create any confusion, because null means nothing. And also it can be used to throw NullPointerException which will be very handy for developer in handling error scenarios if something goes wrong.
8) Adding Object wrapper class in Collection in java -
Object wrapper class can be used when we are working with Collection, because primitive data types cannot be added in Collection Api’s.

Note : whenever you add primitive data type in Collection Api’s it is autoboxed to corresponding object wrapper class.


9) Loading Object wrapper class  at runtime in java  -
Object wrapper classes can be loaded at runtime using reflection. But primitive data type doesn’t provide this support, because reflection can only be used to load classes at runtime.


10) Lot’s of methods are provided by Object wrapper class in java
Object wrapper classes provides so many methods like valueOf(xxx) and xxxValue(), but primitive data type  int does not provide any such methods.




We may set up our eclipse to find out when boxing or unboxing is done in java >
Go to windows, preferences
type error, select Errors/warnings,
type boxing and
then select Error, warning or ignore.
If you select warning, then eclipse will warn you whenever any Autoxing or unboxing is done.


Method overloading in java with
  1. Widening - We discussed a lot about widening in Program 5.2 and 5.3
  2. Autoboxing
  3. Var-args

Now, Let's understand following important concepts where >
  1. AutoBoxing beats Var-args
  2. Widening beats Autoboxing
  3. Widening beats Var-args

  1. widening and then AutoBoxing is not allowed in one operation.
  2. But, AutoBoxing and then widening is allowed in one operation.


  1. AutoBoxing beats Var-args in java
public class AutoboxingBeatsVarargs {
   static void m(Integer i1, Integer i2) {
          System.out.println("Integer i1, Integer i2");
   }
   static void m(Integer...i) {
          System.out.println("int...i");
   }
   public static void main(String[] args) {
          int i = 3;
          m(i, i);
   }
}
/*OUTPUT
Integer i1, Integer i2
*/
Compiler prefers to do AutoBoxing than invoking Var-args. Hence, AutoBoxing beats Var-args

  1. Widening beats Autoboxing in java
public class WideningBeatsAutoboxing {
   public static void main(String[] args) {
          int i = 3;
          m(i);
   }
   static void m(Integer i) {
          System.out.println("Integer");
   }
   static void m(double d) {
          System.out.println("double");
   }
}
/*OUTPUT
double
*/
Compiler prefers to do Widening than doing Autoboxing. Hence, Widening beats Autoboxing

  1. Widening beats Var-args in java
public class WideningBeatsVarargs {
  
   public static void main(String[] args) {
          int i = 3;
          m(i, i);
   }
   static void m(float f1, float f2) {
          System.out.println("float f1, float f2");
   }
   static void m(int... i) {
          System.out.println("int...i");
   }
  
}
/*OUTPUT
float f1, float f2
*/

Compiler prefers to do Widening than invoking Var-args. Hence, Widening beats invoking Var-args


You can remember above 3 conversions in this way >
Widening > Autoboxing > Var-args
(Note: It’s not any standard convention)

  1. widening and then AutoBoxing is not allowed in one operation in java.
As a solution to above program we can perform Widening and then AutoBoxing in multiple steps/operations.
public class WideningAndThenAutoBoxingInMultipleSteps {
   public static void main(String[] args) {
          int i = 3;
          double d = i; // Widening
          Double d2 = d; // AutoBoxing         
   }
}


  1. But, AutoBoxing and then widening is allowed in one operation in java.

public class AutoBoxingAndThenWidening {
   public static void main(String[] args) {
          int i = 3;
          Number num = i; //AutoBoxing and then widening
          Integer i1 = (Integer) num;
   }
}

But how does AutoBoxing and then widening happens internally in one operation?
Java compiler will convert above code into -
public class AutoBoxingAndThenWidening {
   public static void main(String[] args) {
          int i = 3;
          Number num = Integer.valueOf(i); //AutoBoxing and then widening
          Integer i1 = (Integer) num;
          System.out.println(i1);
   }
}
Number num = Integer.valueOf(i);
1) int i is Autoboxed to Integer object,
2) As Number is superclass of Integer, reference variable of Number can refer to Integer object (this is widening of Integer object),

Integer i1 = (Integer) num;
3) num is casted to Integer (java.lang.Object's object was never formed, originally it was Integer's object only but compiler won't trust us for doing such downcasting. Hence, we need explicit casting)



Summary >
In this core java tutorial we learned about Autoboxing and unboxing in java - How it works internally in detail with 10 examples in java language.

Having any doubt? or you you liked the tutorial! Please comment in below section.
Please express your love by liking JavaMadeSoEasy.com (JMSE) on facebook, following on google+ or Twitter.


RELATED LINKS>

Autoboxing and unboxing in java - How it works internally in detail with 10 examples- Widening, AutoBoxing and Var-args

Java caches Integer objects formed from primitive int values between values -128 to 127

10 points on why we are still using primitive data types in java ? When to use primitive type and wrapper classes?

Method overloading with Widening, Autoboxing and Var-args - Who beats whom in java?

Change boxing or Unboxing Setting in eclipse in java - Advantages



Method overloading in java - in detail with programs,10 Features,need of method overloading, overloading main method, Diagram and tabular form of Implicit casting/promotion of primitive Data type

Primitive, Custom/reference Data Types, Integer, Floating-Point, Character and String literal, Escape sequence in java, decimal to hexaDecimal and binary conversion program

Difference between equals method and == operator in java - testing with String and StringBuffer


No comments:

Post a Comment