What Code Does the Compiler Generate for Autoboxing

What code does the compiler generate for autoboxing?

You can use the javap tool to see for yourself. Compile the following code:

public class AutoboxingTest
{
public static void main(String []args)
{
Integer a = 3;
int b = a;
}
}

To compile and disassemble:

javac AutoboxingTest.java
javap -c AutoboxingTest

The output is:

Compiled from "AutoboxingTest.java"
public class AutoboxingTest extends java.lang.Object{
public AutoboxingTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: iconst_3
1: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: aload_1
6: invokevirtual #3; //Method java/lang/Integer.intValue:()I
9: istore_2
10: return

}

Thus, as you can see, autoboxing invokes the static method Integer.valueOf(), and autounboxing invokes intValue() on the given Integer object. There's nothing else, really - it's just syntactic sugar.

Why can't the compiler/JVM just make autoboxing just work?

  • Why did they do it this way?

Every Integer between -128 and 127 is cached by java. They did this, supposedly, for the performance benefit. Even if they wanted to go back on this decision now, it's unlikely that they would. If anyone built code depending on this, their code would break when it was taken out. For hobby coding, this perhaps doesn't matter, but for enterprise code, people get upset and lawsuits happen.

  • Why don't they just cache all Integers used by the program?

All Integers cannot be cached, because the memory implications would be enormous.

  • Why doesn't the JVM always auto unbox to primitive?

Because the JVM cannot know what you wanted. Also, this change could easily break legacy code not built to handle this case.

If the JVM to automatically unboxed to primitives on calls to ==, this issue will actually become MORE confusing. Now you need to remember that == always compares object references, unless the Objects can be unboxed. This would cause yet more weird confusing cases just like the one you stated above.

Rather then worry too hard about this, just remember this rule instead:

NEVER compare objects with == unless you intend to be comparing them by their references. If you do that, I can't think of a scenario in which you'd run into an issue.

Directly casting primitive type to object is fine in Java?

Autoboxing is the automatic conversion that the Java compiler makes
between the primitive types and their corresponding object wrapper
classes.

int intValue = 0;
Integer value = intValue; // by Autoboxing

you can also convert it using valueOf method of wrapper class

Integer value = Integer.valueOf(intValue)

Check What code does the compiler generate for autoboxing? if you still have doubts.

Generate warnings for autoboxing use

Set this setting in your Eclipse,

Preferences -> Java -> Compiler -> Errors/Warnings -> Potential Programming
Problems -> Boxing and unboxing conversions.

What is the difference between Boxing and AutoBoxing in Java?

Boxing is the mechanism (ie, from int to Integer); autoboxing is the feature of the compiler by which it generates boxing code for you.

For instance, if you write in code:

// list is a List<Integer>
list.add(3);

then the compiler automatically generates the boxing code for you; the "end result" in code will be:

list.add(Integer.valueOf(3));

A note about why Integer.valueOf() and not new Integer(): basically, because the JLS says so :) Quoting section 5.1.7:

If the value p being boxed is true, false, a byte, or a char in the
range \u0000 to \u007f, or an int or short number between -128 and 127
(inclusive)
, then let r1 and r2 be the results of any two boxing
conversions of p. It is always the case that r1 == r2.

And you cannot enforce this requirement if you use a "mere" constructor. A factory method, such as Integer.valueOf(), can.

Why do we use autoboxing and unboxing in Java?

Some context is required to fully understand the main reason behind this.

Primitives versus classes

Primitive variables in Java contain values (an integer, a double-precision floating point binary number, etc). Because these values may have different lengths, the variables containing them may also have different lengths (consider float versus double).

On the other hand, class variables contain references to instances. References are typically implemented as pointers (or something very similar to pointers) in many languages. These things typically have the same size, regardless of the sizes of the instances they refer to (Object, String, Integer, etc).

This property of class variables makes the references they contain interchangeable (to an extent). This allows us to do what we call substitution: broadly speaking, to use an instance of a particular type as an instance of another, related type (use a String as an Object, for example).

Primitive variables aren't interchangeable in the same way, neither with each other, nor with Object. The most obvious reason for this (but not the only reason) is their size difference. This makes primitive types inconvenient in this respect, but we still need them in the language (for reasons that mainly boil down to performance).

Generics and type erasure

Generic types are types with one or more type parameters (the exact number is called generic arity). For example, the generic type definition List<T> has a type parameter T, which can be Object (producing a concrete type List<Object>), String (List<String>), Integer (List<Integer>) and so on.

Generic types are a lot more complicated than non-generic ones. When they were introduced to Java (after its initial release), in order to avoid making radical changes to the JVM and possibly breaking compatibility with older binaries, the creators of Java decided to implement generic types in the least invasive way: all concrete types of List<T> are, in fact, compiled to (the binary equivalent of) List<Object> (for other types, the bound may be something other than Object, but you get the point). Generic arity and type parameter information are lost in this process, which is why we call it type erasure.

Putting the two together

Now the problem is the combination of the above realities: if List<T> becomes List<Object> in all cases, then T must always be a type that can be directly assigned to Object. Anything else can't be allowed. Since, as we said before, int, float and double aren't interchangeable with Object, there can't be a List<int>, List<float> or List<double> (unless a significantly more complicated implementation of generics existed in the JVM).

But Java offers types like Integer, Float and Double which wrap these primitives in class instances, making them effectively substitutable as Object, thus allowing generic types to indirectly work with the primitives as well (because you can have List<Integer>, List<Float>, List<Double> and so on).

The process of creating an Integer from an int, a Float from a float and so on, is called boxing. The reverse is called unboxing. Because having to box primitives every time you want to use them as Object is inconvenient, there are cases where the language does this automatically - that's called autoboxing.

Can please anybody explain me this Autoboxing?

The Java compiler applies unboxing when an object of a wrapper class is:

  • Passed as a parameter to a method that expects a value of the
    corresponding primitive type.
  • Assigned to a variable of the corresponding primitive type.

So, as there was a suitable method for Integer class, which is void go(Number n) because Number class is super class of Integer and this method accepts Integer objects as well.
So compiler didn't need to unbox the Integer to int.

What is difference between wrapper and Auto Boxing/Unboxing in java?

Auto-boxing and auto-unboxing is just the compiler silently helping you create and use primitive wrapper objects.

For example, the int primitive type has wrapper class called Integer. You wrap and unwrap as follows:

int myInt = 7;

// Wrap the primitive value
Integer myWrappedInt = Integer.valueOf(myInt);

// Unwrap the value
int myOtherInt = myWrappedInt.intValue();

With auto-boxing and auto-unboxing, you don't have to do all that boiler-plate stuff:

int myInt = 7;

// Wrap the primitive value
Integer myWrappedInt = myInt; // Compiler auto-boxes

// Unwrap the value
int myOtherInt = myWrappedInt; // Compiler auto-unboxes

It's just a syntactic sugar, handled by the compiler. The generated byte code is the same.



Related Topics



Leave a reply



Submit