Skip to main content
Logo image

Section 10.2 Wrapper classes

As we discussed in the previous section, one of the limitations of the ArrayList class (which is actually a limitation of Java’s generic types more generally) is that the element type of an ArrayList must be a reference type. So we can make an ArrayList<String> but not an ArrayList<int>. So what are we supposed to do if we want to make a growable, shrinkable collection of int or double values?
Java’s solution to this problem is to define wrapper classes, classes that exist to provide a reference type that wraps up a single value of a given primitive type. These types are defined in the java.lang pacakge and have names that are the capitalized, unabbreviated names of the corresponding primitive types: Integer, Double, and Boolean.
As reference types, these types can be used as the element type of an ArrayList: ArrayList<Integer>, ArrayList<Double>, and ArrayList<Boolean>. As we’ll see Java provides a bit of extra support for these types, automatically converting between wrapper types and the corresponding primitive values in many contexts.
There are also a few static utility methods and constants defined in the wrapper classes related to the corresponding primitive type.

Subsection 10.2.1 Using wrapper classes with ArrayList

The main use of wrapper types is as type parameter in an ArrayList declaration. If what we really want is a list of int values we can declare an ArrayList<Integer>.
Once we’ve declared an ArrayList with a wrapper class for an element type, how do we create instances of the wrapper class to put in it?
There are three ways, but in fact we almost only ever need one of them. The oldest, and worst, way is to construct a new instance of the wrapper class with a the constructor that takes a single value of the corresponding primitive type. These constructors exist but have been deprecated which means they still exist because removing them would break old code but they are now considered a mistake.
ArrayList<Integer> integers = new ArrayList<>();
ArrayList<Double> doubles = new ArrayList<>();

// BAD: don't do this. But it does work
integers.add(new Integer(42));
doubles.add(new Double(3.14));
Slightly better is to use the static utility methods, valueOf, defined in the wrapper classes that take a primitive value and return a wrapped instance.
// Slightly better: also works. But also not necessary as we'll see
integers.add(Integer.valueOf(42));
doubles.add(Double.valueOf(3.14));
The advantage of the valueOf methods compared to the constructors is that the methods don’t have to create a new object each time. This can save a lot of memory by reusing the same object for the same commonly wrapped primitive value. For example, making an array list containing a million zeros obtained with with Integer.valueOf(0) would use only one object to represent all the zeros whereas if we made them with new Integer(0) Java would have to allocate a million different objects, each holding the same 0 value, using a million times as much memory.
But the right way to do this is to ignore the wrapper types and let a feature of Java called autoboxing take care of it for us.
// The right way
integers.add(42);
doubles.add(3.14);
Autoboxing is the automatic conversion that the Java compiler makes between primitive types and their corresponding object wrapper classes. The Java compiler applies autoboxing when a primitive value is passed as a parameter to a method that expects an object of the corresponding wrapper class or assigned to a variable of the corresponding wrapper class. So when we call add on an ArrayList<Integer> the compiler knows add expects an Integer. If it sees that we’re passing an int it automatically gets an instance of Integerto wrap it, basically as if we had written a call to Integer.valueOf.
An automatic conversion going in the other direction called unboxing happens when a value of a wrapper type is passed as a parameter or assigned to a variable that expects the corresponding primitive type. This means we can write code like this:
int i = integer.get(0);
double d = doubles.get(0);
The values actally returned by get in those two lines are Integer and Double but Java unwraps them and assigns the underlying value to the primitive variables i and d.
Thanks to autoboxing and unboxing we almost never need to use the wrapper types anywhere except as the type parameters when declaring an ArrayList. For the most part we can just use primitive values and everything will work out fine. Unfortunately they are a few edge cases where it doesn’t which we’ll discuss below.

Activity 10.2.1.

Which of the following is the correct way to create an ArrayList of integers?
  • ArrayList[int] numbers = new ArrayList<>();
  • The square brackets [] are only used with arrays, not ArrayLists.
  • ArrayList<String> numbers = new ArrayList<>();
  • String is not the correct type since this is for an array of integers.
  • ArrayList<int> numbers = new ArrayList<>();
  • ArrayLists cannot hold primitive types like int. You must use the wrapper class Integer.
  • ArrayList<Integer> numbers = new ArrayList<>();
  • The wrapper class Integer is used to hold integers in an ArrayList.

Activity 10.2.2.

Activity 10.2.3.

Here’s an example of code that uses autoxboxing to add values to an ArrayList<Integer>. What will print when the following code executes?
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(2, 4);
list1.add(5);
System.out.println(list1);
You can step through the code above by clicking on this Java Visualizer.
  • [1, 2, 3, 4, 5]
  • This would be true if all the add method calls were add(value), but at least one is not.
  • [1, 4, 2, 3, 5]
  • This would be true if add(2, 4) was add(1, 4) instead
  • [1, 2, 4, 3, 5]
  • The add(2, 4) will put the 4 at index 2, but first move the 3 to index 3.
  • [1, 2, 4, 5]
  • This would be true if the add(2, 4) replaced what was at index 2, but it actually moves the value currently at index 2 to index 3.

Subsection 10.2.2 An autoboxing subtlety

As mentioned above, there are a few times when we can’t completely ignore what’s going on with autoboxing and unboxing. If we stick strictly within the AP curriculum we won’t hit them but we don’t have to go very far outside the bounds to run into one.
The AP curriculum covers the ArrayList method E remove(int) which takes an int argument specifying the index of the element to remove. That’s fine. But there’s another remove method, boolean remove(Object) that takes any reference type as an argument ArrayList and either removes the first object in the list that is equals to it and returns true or returns false if there was no such object to remove.
The subtlety is this. What happens if we have an ArrayList<Integer> and then call remove(42)? Should it call remove(int), and remove the element at index 42 or should it autobox 42 and remove the first element of the list whose value is an Integer wrapping the value 42?
As it happens, Java goes with remove(int). Which means the calls to remove below behave very differently:
ArrayList<Integer> nums = new ArrayList<>();
nums.add(10);
nums.add(20);
nums.add(30);

nums.remove(Integer.valueOf(0))
nums.remove(0);
nums.remove(Integer.valueOf(20))
nums.remove(20);
The first call to remove does nothing and returns false because there’s no 0 in the list. The second call removes the first element of the list, 10, because the argument is treated as the index 0, not a value. The third call successfully removes the 20 from the list. And the fourth call crashes with an IndexOutOfBoundsException because 20, as an index, is way too big for the list which now only has one element in it.

Activity 10.2.4.

Remember that the remove(int index) method removes a value from an ArrayList at a specific position decreasing the size of the list by one and shifting down the items that were at higher indexes in the array by one position. It also returns the item that was removed.
What will the following code print out? Try to guess before you run it. Were you surprised? Read the note below.

Activity 10.2.5.

What will print when the following code executes?
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.remove(2);
System.out.println(list1);
  • [2, 3]
  • This would be true if it was remove(0)
  • [1, 2, 3]
  • The remove will remove a value from the list, so this can’t be correct.
  • [1, 2]
  • The 3 (at index 2) is removed
  • [1, 3]
  • This would be true if it was remove(1)
You can step through the code above by clicking on the following RemoveExample.

Activity 10.2.6.

What will print when the following code executes?
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.set(2, 4);
list1.add(2, 5);
list1.add(6);
System.out.println(list1);
  • [1, 2, 3, 4, 5]
  • The set will replace the item at index 2 so this can not be right.
  • [1, 2, 4, 5, 6]
  • The add with an index of 2 and a value of 5 adds the 5 at index 2 not 3. Remember that the first index is 0.
  • [1, 2, 5, 4, 6]
  • The set will change the item at index 2 to 4. The add of 5 at index 2 will move everything else to the right and insert 5. The last add will be at the end of the list.
  • [1, 5, 2, 4, 6]
  • The add with an index of 2 and a value of 5 adds the 5 at index 2 not 1. Remember that the first index is 0.
You can step through the code above by clicking on the following Example1.

Subsection 10.2.3 Summary

  • The Integer class and Double class are wrapper classes that create objects from primitive types.
  • (AP 4.7.A.1) The Integer class and Double class are part of the java.lang package.
  • (AP 4.7.A.1) An Integer object is immutable, meaning once an Integer object is created, its attributes cannot be changed. A Double object is immutable, meaning once a Double object is created, its attributes cannot be changed.
  • (AP 4.7.A.2) Autoboxing is the automatic conversion that the Java compiler makes between primitive types and their corresponding object wrapper classes. This includes converting an int to an Integer and a double to a Double. The Java compiler applies autoboxing when a primitive value is:
    • passed as a parameter to a method that expects an object of the corresponding wrapper class
    • assigned to a variable of the corresponding wrapper class
  • (AP 4.7.A.3) Unboxing is the automatic conversion that the Java compiler makes from the wrapper class to the primitive type. This includes converting an Integer to an int and a Double to a double. The Java compiler applies unboxing when a wrapper class object 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
  • (AP 4.7.A.4) The following class Integer methodβ€”including what it does and when it is usedβ€”is part of the Java Quick Reference: static int parseInt(String s) returns the String argument as a signed int.
  • (AP 4.7.A.5) The following class Double methodβ€”including what it does and when it is usedβ€”is part of the Java Quick Reference: static double parseDouble(String s) returns the String argument as a signed double.
You have attempted of activities on this page.