Autoboxing and unboxing in Java

Today we will talk about autoboxing and unboxing. This is one of the significant changes made to JDK 5. Now developers can write cleaner code, but misunderstanding the operation of this mechanism can lead to poor performance.

Auto Pack


This is an automatic encapsulation of a primitive type in its equivalent wrapper class whenever an object of this type is required. There is a great article from ffriend about encapsulation and other OOP principles . Autoboxing occurs:


  1. When assigning a primitive type value to a variable of the corresponding wrapper class.
  2. When passing a primitive type to a parameter of a method that expects its corresponding wrapper class.

Examples


Up to JDK 5
public class Main {
    public static void main(String[] args) {
       Integer iOb = new Integer(7);
       Double dOb = new Double(7.0);
       Character cOb = new Character('a');
       Boolean bOb = new Boolean(true);
       method(new Integer(7));
    }
    public static void method(Integer iOb) {
      System.out.println("Integer");
    }
}

Starting with JDK 5
public class Main {
    public static void main(String[] args) {
       Integer iOb = 7;
       Double dOb = 7.0;
       Character cOb = 'a';
       Boolean bOb = true;
       method(7);
    }
    public static void method(Integer iOb) {
      System.out.println("Integer");
    }
}


Auto Unpack


This is a conversion of a wrapper class to its corresponding primitive type. If the wrapper class was null when unpacking , a java.lang.NullPointerException will be thrown .

Unboxing happens:
  1. When assigning an instance of a wrapper class to a variable of the corresponding primitive type.
  2. In expressions in which one or both arguments are instances of wrapper classes (except for the operation == and! =).
  3. When passing an object of a wrapper class to a method that expects an appropriate primitive type.

Let's take a closer look.

1. Upon assignment


Up to JDK 5
int i = iOb.intValue();
double d = dOb.doubleValue();
char c = cOb.charValue();
boolean b = bOb.booleanValue();

Starting with JDK 5
int i = iOb;
double d = dOb;
char c = cOb;
boolean b = bOb;

2. In expressions


Since arithmetic and comparison operators (exception == and! =) Apply only to primitive types, we had to manually unpack them, which significantly reduced the readability of expressions, making them bulky, and the code as a whole.
Integer iOb1 = new Integer(5);
Integer iOb2 = new Integer(7);
System.out.println(iOb1.intValue() > iOb2.intValue());

Thanks to auto-unpacking, we can safely write expressions without using conversion methods. Now the Java compiler is following this.
System.out.println(iOb1 > iOb2);
System.out.println(iOb1 + iOb2);

When comparing wrapper classes with the == or! = Operator, comparisons are made by reference rather than by value, and confusion can occur. For example, what do you think will be displayed when the following code is executed?
Integer iOb1 = 100;
Integer iOb2 = 100;
System.out.println(iOb1 == iOb2);
Integer iOb3 = new Integer(120);
Integer iOb4 = new Integer(120);
System.out.println(iOb3 == iOb4);
Integer iOb5 = 200;
Integer iOb6 = 200;
System.out.println(iOb5 == iOb6);

Answer: in the first case - true, in the second and third - false.
In the first case, the static method java.lang.Integer.valueOf (int) is actually called, which caches values ​​from -128 to 127 (the upper limit can be changed) and, when reused, removes them from the so-called pool (a set of initialized and ready-to-use objects) ) In the second, objects are created explicitly, therefore they have different references.

3. When passed to a method


public class Main {
    public static void main(String[] args) {
        Integer iOb  = 10;
        method(iOb);
    }
    public static void method(int i) {
       System.out.println("int");
   }
}

An int will be displayed, but it is worth noting that if overload with the corresponding wrapper class is implemented for a method, it will be called.
public class Main {
    public static void main(String[] args) {
        Integer iOb  = 10;
        method(iOb);
    }
    public static void method(int i) {
       System.out.println("int");
   }
    public static void method(Integer iOb) { //Будет вызван данный метод
       System.out.println("Integer");
   }
}

It should also be remembered that autopacking and autopacking do not work for arrays.
public class Main {
    public static void main(String[] args) {
        Integer[] iObs = new Integer[] {5, 10, 50, 2, 7};
        method(iObs); //Ошибка компиляции
    }
    public static void method(int ... i) {
       System.out.println("int[]");
   }
}

Poor performance


Wrapper classes are immutable, so each auto-packaging (except for values ​​from pool) creates a new object, which can lead to unreasonable memory consumption.
public static Integer sumBeforeInclusive(Integer number) {
        Integer iOb = number;
        if (number > 1) iOb += sumBeforeInclusive(number - 1);
        return iOb;
    }

Primitive types and their wrapper classes


Whole numbers
  • byte - Byte
  • short - Short
  • int - Integer
  • long - Long


Floating point numbers
  • float - float
  • double - Double


Characters
  • char - Character


Boolean values
  • boolean - boolean


Also popular now: