Friday, October 7, 2011

Autoboxing and Unboxing Part - 2


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 arguements 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 <= and >=
        
        Integer intObject1 = 100;
        Integer intObject2 = 101;
        Integer intObject3 = 128;
        Integer intObject4 = 129;
       
        if(intObject1 <= intObject2)
            System.out.println("intObject1 is <= intObject2");
        else
            System.out.println("intObject1 is > intObject2");
        if(intObject4 >= intObject3)
            System.out.println("intObject4 is >= intObject3");
        else
            System.out.println("intObject4 is < intObject3");        
        O/P:
        intObject1 is <= intObject2
        intObject4 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)
            System.out.println("intObject1 is <= intObject2");
        else
            System.out.println("intObject1 is > intObject2");
        if(intObject4 >= intObject3)
            System.out.println("intObject4 is >= intObject3");
        else
            System.out.println("intObject4 is < intObject3");        
        O/P:
        intObject1 is <= intObject2
        intObject4 is >= intObject3    
        

Conclusion

This new feature in J2SE 5.0 has both advantanges and disadvantess, 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.    

No comments: