Bits of Java – Episode 12: Wrapper Classes
In this episode we will talk about the Java wrapper classes for the primitive types. But first, let me share with you some wonderful news: this week I passed the Orcale Java SE11 Programmer I! Writing this blog hepled me a lot to memorize and to clarify the concepts. But do not worry, I am not done yet with the full certification, so you can expect a lot of other posts in the next weeks!
But now, let’s go back to today’s topic: wrapper classes . You probably all know that in Java there are eight primitive types (
boolean). When you initialize one of these types in your program, you are not creating any object in memory, but you are simply writing that value in the memory space allocated to it.
This is what mainly differentiates them from all the other types in Java, which are the reference types. Another difference is that, while you can assign
null to a reference variable, you cannot do it for a primitive type. Moreover, you cannot call methods on a primitive type, while you can instead do it for a reference type.
OK, we got the differences; but when do the wrapper classes come into play? And why?
Each primitive type has its own wrapper class, which is a reference type. You can think of them as the “reference type version” of a primitive type. In the following table each primitive type is shown with its corresponding wrapper class.
|Primitive Type||Wrapper Class|
The wrapper classes are convenient because in a lot of cases Java expects you to work with objects and not with primitives.
ArrayList<int> list = new ArrayList<int>(); //DOES NOT COMPILE ArrayList<Integer> list2 = new ArrayList<Integer>(); //THIS IS OK
int primitiveType = null; //DOES NOT COMPILE Integer referenceType = null; //THIS IS OK
Let’s look at how to create a wrapper class object. You have several possibilities, among which:
- using the
newkeyword and passing the corresponding primitive value:
Integer number = new Integer(3);
- using the
valueOf()and passing the corresponding primitive value:
Integer number = Integer.valueOf(3);
Note that this method is actually preferred with respect to the previous one, since it allows to use some kind of caching mechanism (something similar to what the string pool does for
String, remember? If not, check out here).
- using the
valueOf()and passing a
Integer number = Integer.valueOf("3"); /* * If the String is not properly formatted, you will get * a NumberFormatException at runtime */ Integer number2 = Integer.valueOf("ciao");
There exists also a corresponding
static method to parse back the primitive type from the
int primitiveType = Integer.parseInt("3");
- directly passing the primitive value:
Integer number = 3;
This is probably the most practical way to create a wrapper class object, and it was introduced with Java 5, so one does not have to think too much while coding. The process for which the compiler automatically recognizes that we want to put a primitive into its corresponding wrapper class is called autoboxing. This also works in the opposite direction, namely from the wrapper class to the primitive, and the process is called unboxing.
ArrayList<Integer> list = new ArrayList<Integer>(); list.add(3); //AUTOBOXING int number = list.get(0); //UNBOXING
Although very useful, the fact that the compiler automatically takes care of autoboxing and unboxing for us, can create some confusion in certain situations.
ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.remove(1); System.out.println(list.get(0)); //prints 1 ArrayList<Integer> list2 = new ArrayList<Integer>(); list2.add(1); list2.add(2); list2.remove(new Integer(1)); System.out.println(list2.get(0)); //prints 2
To understand this example, we have to recall that the method
ArrayList has two signatures:
boolean remove(Object object) E remove(int index)
The first one accepts as parameter the
Object to remove and it returns
false depending on whether the removal was successful or not; while the second one accepts the index of the element we want to remove and returns the
Object that got removed.
So, coming back to our example, in the first list we are using
remove(1), so we are passing an
int as parameter. The compiler then will use the version of
remove() which exactly matches the type of the parameter, since one exists, and will not apply any autoboxing here to convert that
1 to an
Integer. That’s why this results in the removal of the element at index 1.
In the second list, instead, we are passing an
Integer, so the compiler recognizes as matching version for the
remove() method, the one which takes an
Object as parameter, resulting now in removing not the element at index 1, but the element corresponding to the value of “1”, so the element at index 0.
So, concluding, keep in mind that every primitive type has its own reference-type version, which can be used as any other reference type. Passing from the primitive type to the corresponding wrapper type is done, in some cases, automatically by the compiler through autoboxing and unboxing, while in others, this is not the case, so you need to keep track of what you are doing and what you want to achieve to avoid unexpected results!
In next week topic we will discuss about the conversion between array and list.
by Ilenia Salvadori