AutoBoxing in Java 5.0

1)Introduction

In the latest version of J2SE 5.0 released by Sun, Autoboxing is one of the new feature. Before J2SE 5.0, working with primitive types required the repetitive work of converting the primitive types into wrapper classes and vice – versa. Sometimes the purpose of conversion is just for some API call, after which the results have to be converted into original form which is very frustrating . Auto-boxing and Auto-Unboxing enables the primitive types to be converted into respective wrapper objects and the other way around.This article gives some insight about the importance of this new feature and how it can be used in the real-world programming. The following are some of the popular books available for learning Java 1.5

2)Boxing/Unboxing

Let’s take a small example of incrementing the value of Integer Object for understanding the concept of Boxing/Unboxing.

Before Java 5
int intPrimitive = intObject.intValue();
intPrimitive++;
intObject = new Integer(intPrimitive);

Using Java 5

Integer intObject = new Integer(10);
intObject++;

The output for the above examples will be same. In the first example we are creating an Integer object, unwrapping it to primitive value,incrementing the primitive value, re-wrapping it to Integer object again.

In the second example when the compiler encounters the line intObject++ compiler unwraps Integer object to primitive type, increments it and rewraps to Integer Object again,So When the compiler got to the line intObject++; it substitues the code which will be something like this:

 Integer.valueOf(intObject.intValue()+1);

or

	int intPrimitive = intObejct.intValue();
	intPrimitive++;
	intObject = new Integer(intPrimitive);

Below example’s show different ways of Boxing/Unboxing.

 Boolean isValid = false;		// Boxing

		Short shortObject = 200;	        // Boxing

		if(shortObject list = new ArrayList();
	          for(int i = 0; i < 10; i++){
        	     list.add(i); 		       // Boxing
          	}

3)How Overloading works for Boxing/Unboxing ?

General Rule: Arguments are implicitly widened to match method parameters. Lets assume that we are having a function which takes an int as paratmeter.

 public void testWidening(int i){
	// Business Logic
	}

	byte b = 25;
	testWidening(b);

Now instead of passing int as an argument if we pass byte or short as arguments then these arguments are implicitly widened to match the testWidening method that takes an int.

Overloading with Boxing

Scenario 1: overloaded functions which take int and Integer as parameters.

 void testWidening(int j){
	    	System.out.println('method call for primitive int');
    	    }
   	    void testWidening(Integer k){
		System.out.println('method call for Integer Object');
    	    }

	    int i = 30;
            new Test().testWidening(i);

O/P:

  method call for primitive int

Pretty straight forward output, int is passed as an argument and the function which is taking int as parameter has been invoked.
Scenario 2: overloaded functions which take long and Integer as parameters.

 void testWidening(long j){
 	    	System.out.println('method call for primitive long');
	    }
	    void testWidening(Integer k){
	    	System.out.println('method call for Integer Object');
	    }

O/P:

  method call for primitive long

Since pre-existing/older versions of code should function the way it used to be, the compiler will always choose the older conversion of widening rather then the new one.Here the function which takes long as a parameter is choosen over the function which takes Integer as a parameter.
Scenario 3: overloaded functions which take Long and Integer as parameters.

 void testWidening(Long j){
 	   	System.out.println('method call for Long Object');
	    }
	    void testWidening(Integer k){
	    	System.out.println('method call for Integer Object');
	    }

O/P:

  method call for Integer Object

As expected now the method which is taking Integer object as parameter has been called over the method which is taking Long object as parameter.
Scenario 4: overloaded functions which take int and long as parameters and argument is an Integer object.

 void testWidening(int i){
        		System.out.println('in int method');
    		}
    		void testWidening(long j){
        		System.out.println('in long method');
    		}

        	new Test().testWidening(new Integer(10));

O/P:

  in int method

The above example shows how Unboxing is done in Java 5. Here we are passing Integer object as an argument and the method which takes int as parameter has been invoked.

Widening Reference Variables

 class Shape{
        	//common methods
    	}
	public class Rectangle extends Shape{
    		public void testWidening(Shape s){
	        	System.out.println('Here I am');
    		}
		public static void main(String a[]){
		    Rectangle r = new Rectangle();
		    r.testWidening(r);
    		}
	}

O/P:

  Here I am

Here the testWidening method needs Shape object, and Rectangle IS-A Shape. Now let’s look this example.

 void testWidening(Long i){
        	System.out.println('method call for Long Object');
    	}
    	public static void main(String a[]){
        	test t = new test();
        	t.testWidening(new Integer(10));
    	}

O/P:

  Compile Time Error

It’s not legal to widen from one wrapper class to another, The reason is all the wrapper classes like BigDecimal, BigInteger, Byte, Double, Float,Integer, Long, Short extend Number class and its not valid to say Integer IS-A Long.

3)How ==, !=, = works for Boxing/Unboxing ?

Let’s look at the below example’s.

  • Example for ==
 Integer intObject1 = 100;
        Integer intObject2 = 100;
        Integer intObject3 = 128;
        Integer intObject4 = 128;

        if(intObject1 == intObject2)
            System.out.println('intObject1 and intObject2 are equal');
        else
            System.out.println('intObject1 and intObject2 are not equal');

         if(intObject3 == intObject4)
            System.out.println('intObject3 and intObject4 are equal');
        else
            System.out.println('intObject3 and intObject4 are not equal');

O/P:

  intObject1 and intObject2 are equal
	     intObject3 and intObject4 are not equal

General guess would be false in both cases.

Here there is a difference in the output’s of two if statements because in order to save memory when primitive types are boxed into the wrapper types, the JVM allocates memory and creates a new object. But for some special cases, the JVM reuses the same object, two instances of the following wrapper objects 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
  • Example for !=
 if(intObject1 != intObject2)
            System.out.println('intObject1 and intObject2 are not equal');
        else
            System.out.println('intObject1 and intObject2 are equal');
        if(intObject3 != intObject4)
            System.out.println('intObject3 and intObject4 are not equal');
        else
            System.out.println('intObject3 and intObject4 are equal');

O/P:

 intObject1 and intObject2 are equal
	intObject3 and intObject4 are not equal

The ouput is as expected, Since the values of intObject1 and intObject 2 are below 128, they are considered as equal and intObject3 and intObject4 are considered as not equal.

  • Example for =
 Integer intObject1 = 100;
        Integer intObject2 = 101;
        Integer intObject3 = 128;
        Integer intObject4 = 129;

        if(intObject1  intObject2');
        if(intObject4 >= intObject3)
            System.out.println('intObject4 is >= intObject3');
        else
            System.out.println('intObject4 is <intObject3');

O/P:

 intObject1 is = intObject3

This time we have changed 2nd and 4th declarations from Integer to Int still the output is the same.

 Integer intObject1 = 100;
        int 	intObject2 = 101;
        Integer intObject3 = 128;
        int 	intObject4 = 129;

        if(intObject1  intObject2');
        if(intObject4 >= intObject3)
            System.out.println('intObject4 is >= intObject3');
        else
            System.out.println('intObject4 is <intObject3');
	

O/P:

 intObject1 is = intObject3

Conclusion

This new feature in J2SE 5.0 has both advantages and disadvantages, it all depends on where and how are we using the feature. It is recommended by SUN to use them only when there is an “impedance mismatch” between reference types and primitives, for example, when you have to put numerical values into a collection. It is not appropriate to use autoboxing and unboxing for scientific computing, or other performance-sensitive numerical code. An Integer is not a substitute for an int; autoboxing and unboxing blur the distinction between primitive types and reference types, but they do not eliminate it.

Javabeat has published many of the good articles related to Java 1.5 version. This list will help you to learn some of the notable features introduced with the version 1.5, please have a look on these articles when time permits. Don’t forget to leave your feedback on the comments section. This helps us to provide better content for you.

The above article would provide the higher level of understanding on each concept. There are many other great features introduced in the Java 1.5 version. Hope this helps you!!

If you would like to receive future mails on Java articles, please subscribe here.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Comments

  1. Good article.Thanks

  2. Really its a good effort. keep it up man :)

Speak Your Mind

*