User Professor Hans Noodles
Professor Hans Noodles
Level 41

Wrappers, unboxing, and boxing

Published in the Java Developer group
Hi! You are already well acquainted with primitive types, and have worked quite a bit with them. In programming (and Java in particular), primitives have many advantages: they use little memory (and thus make the program more efficient) and have a clearly delineated range of values. However, while learning Java, we've already often repeated the mantra "everything in Java is an object". But primitives directly contradict those words. They aren't objects. So, is our "everything is an object" principle false? Actually, it's not. In Java, every primitive type has a twin brother, a wrapper class. Wrappers, unboxing, and boxing - 1 What's a wrapper? A wrapper is a special class that stores a primitive internally. But because it's a class, you can create instances of it. They store the primitive values internally, but are still real objects. Wrapper class names are very similar to (or exactly the same as) the names of their corresponding primitives. So, they are easy to remember.
Wrapper Classes for Primitive Data Types
Primitive Data Types Wrapper Classes
int Integer
short Short
long Long
byte Byte
float Float
double Double
char Character
boolean Boolean
Wrapper objects are created the same way as any other object:

public static void main(String[] args) {

   Integer i = new Integer(682);
  
   Double d = new Double(2.33);
  
   Boolean b = new Boolean(false);
}
Wrapper classes let us mitigate the shortcomings of primitive types. The most obvious is that primitives don't have methods. For example, they don't have a toString() method, so you can't, for instance, convert an int to a String. But the Integer wrapper class makes this easy.

public static void main(String[] args) {

   Integer i = new Integer(432);
  
   String s = i.toString();
}
However, converting in the other direction can be trickier. Let's say we have a String, which we know for sure contains a number. Regardless, there's no native way to use a primitive int to extract the number from the String and convert it to a number. But, we can with the wrapper classes.

public static void main(String[] args) {

   String s = "1166628";

   Integer i = Integer.parseInt(s);

   System.out.println(i);
}
Output: 1166628 We successfully extracted a number from the String and assigned it to the Integer reference variable i. By the way, regarding references. You already know that arguments are passed to methods in different ways: primitives by value, and objects by reference. You can use this knowledge when creating your own methods: for example, if your method uses fractional numbers but you need logic to pass by reference, you can pass Double/Float arguments to the method instead of double/float. In addition to wrapper classes' methods, their static fields can also be very convenient. For example, imagine you have the following task: display the maximum possible int value, followed by the minimum possible value. This problem seems rather basic. But without Google, it's unlikely you could do it. But wrappers allow you to easily handle such "mundane tasks":

public class Main {
   public static void main(String[] args) {

       System.out.println(Integer.MAX_VALUE);
       System.out.println(Integer.MIN_VALUE);
   }
}
These fields keep you from getting distracted from accomplishing more serious tasks. Not to mention the fact that typing in 2147483647 (which happens to be the value of MAX_VALUE) is no minor feat! :) Moreover, in a previous lesson, we pointed out that wrapper objects are immutable.

public static void main(String[] args) {

   Integer a = new Integer(0);
   Integer b = new Integer(0);

   b = a;
   a = 1;
   System.out.println(b);
}
Output: 0 The state of the object originally pointed to by a didn't change (because the value of b would have also changed). As with Strings, instead of changing the wrapper object's state, an entirely new object is created in memory. So, why did Java's creators ultimately decide to leave primitive types in the language? Since everything should be an object, and we've got wrapper classes that can express everything that primitives express, why not only keep the wrappers in the language and remove the primitives? The answer is simple: performance. Primitive types are called primitive because they lack many of the "heavyweight" features of objects. Yes, objects have many convenient methods, but you don't always need them. Sometimes, all you need is the number 33, or 2.62, or true/false. In situations where the advantages of objects don't matter and aren't required for the program to function, primitives are far better suited to the task.

Autoboxing/unboxing

In Java, a feature of primitives and their wrappers is autoboxing/unboxing. Wrappers, unboxing, and boxing - 2 Let's dig into this concept. As we've already learned, Java is an object-oriented language. That means that all programs written in Java are made of objects. Primitives are not objects. But even so, a wrapper variable can be assigned a primitive value. This process is called autoboxing. Similarly, a primitive variable can be assigned a wrapper object. This process is called unboxing. For example:

public class Main {
   public static void main(String[] args) {
       int x = 7;
       Integer y = 111;
       x = y; // Unboxing
       y = x * 123; // Autoboxing
   }
}
In line 5, we assign y, which is an Integer object, to the primitive x. As you can see, we don't have to take any additional steps: the compiler knows that int and Integer are, essentially, the same thing. That's unboxing. Something similar is happening with autoboxing on line 6: the primitive value (x * 123) is easily assigned to object y. This is an example of autoboxing. That's why the term includes the word "auto": because you don't have to do anything special to assign primitives to their corresponding wrapper objects (and vice versa). It all happens automatically. Convenient, huh? :) We see another example of the convenience of autoboxing/unboxing when working with methods. This is because method arguments are also autoboxed and unboxed. For example, if a method takes two Integer objects as inputs, we can easily pass ordinary ints instead!

public class Main {
   public static void main(String[] args) {

       printNumber(7);// A standard int, not even an int variable
   }

   public static void printNumber(Integer i) {
       System.out.println("You entered the number " + i);
   }
}
Output: You entered the number 7 It works in the other direction, too:

public class Main {
   public static void main(String[] args) {

       printNumber(new Integer(632));
   }

   public static void printNumber(int i) {
       System.out.println("You entered the number " + i);
   }
}
An important point you need to remember is this: autoboxing and unboxing don't work for arrays!

public class Main {
   public static void main(String[] args) {

       int[] i = {1,2,3,4,5};
      
       printArray(i);// Error, this won't compile!
   }
  
   public static void printArray(Integer[] arr) {
       System.out.println(Arrays.toString(arr));
   }
}
Attempting to pass an array of primitives to a method that takes an array of objects will result in a compilation error. In conclusion, let's briefly compare primitives and wrappers one more time. Primitives:
  • Have performance advantages
Wrappers:
  • Allow us to not violate the "everything is an object" principle, which means that numbers, characters, and boolean values don't violate this concept
  • Expand the possibilities for working with these values by providing convenient methods and fields
  • Are necessary when a method only works with objects
Comments (11)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
John H Level 15, Charlotte, United States
27 April 2021
To me it would make more sense if autoboxing/unboxing, was called autowrapping/unwrapping, since it refers to wrapper classes, not boxer classes... Go figure!
Angel Li Level 18, Fremont, United States
26 June 2020
Say the Integer wrapper class is a box. The wrapper class contains int inside the box. Unwrapping is going from Integer to int, so basically unwrapping the box to get the int. Autowrapping is going from int to Integer, like a present is going to go inside the box. That's why it's auto.
Peter Schrijver Level 23, Hilversum, Netherlands
11 June 2020
Great material and good explanation
YSS Level 16, New York City, United States
8 December 2019
This article is technically wrong. Not everything in Java is an object. It's not because there are wrapper classes that all of a sudden primitives are objects. Therefore one should say 'Almost everything in Java is an Object' as some good books do these days.
Binesh Level 16, India
24 September 2019
Nice! Well Explained.
Renat Mukhametshin Level 16, Pervouralsk, Russain Federation
8 August 2019
ohh yeah!!
reka Level 19, Dunaujvaros, Hungary
11 March 2019
Boxing / autoboxing happens automatically and allows you to add an int to an ArrayList of Integers or add an Integer variable to an array of primitive int values: int i = 8; List<Integer> lst = new ArrayList<>(); lst.add(i); System.out.println(lst); // [8] System.out.println(lst.get(0) instanceof Integer); // true int[]arr = new int[1]; arr[0] = new Integer(5); System.out.println(Arrays.toString(arr)); // [5]
Fadi AlSaidi Level 13, Carrollton, United States
9 February 2019
Glad this was explained. I was wondering about this for a while.