Module 4: Primitive Wrapper Classes
Module Overview
Learn about primitive wrapper classes, autoboxing, and unboxing in Java.
Learning Objectives
- Understand what Java collections are and when to use them
- Learn the core interfaces of the Collections Framework
- Explore implementation classes for Lists, Sets, and Maps
- Utilize collection utility methods for common operations
Key Concepts
Java Collections Framework Overview
The Java Collections Framework (JCF) is a unified architecture for representing and manipulating collections of objects. It provides standard data structures like lists, sets, and maps, along with algorithms for searching, sorting, and manipulating these collections.
Core Collection Interfaces:
- Collection - The root interface with basic methods like add(), remove(), and contains()
- List - An ordered collection that allows duplicate elements
- Set - A collection that cannot contain duplicate elements
- Queue - A collection designed for holding elements prior to processing
- Map - An object that maps keys to values, with no duplicate keys allowed
Primitive Wrapper Classes
What are they?
There is a set of classes that we refer to as "primitive wrapper" classes that correspond to the primitive types in Java. For example, the double primitive type has a corresponding Double class.
They're classes that contain a member variable of the relevant primitive type and some helpful additional methods.
Note that primitive types are not objects and are thus stored by value. The wrapper types are objects and are thus stored by reference. So a variable of type, Integer , actually contains a reference to an Integer object. But a variable of type, int , simply contains the integer value of that int. Because the wrapper classes are object types, remember to use equals() when comparing instances of these wrapper classes: do NOT use == (which will make a reference comparison instead of a value comparison!)
Primitive Types and Their Wrapper Classes:
Primitive Type | Wrapper class |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
Notice that most of the wrapper class names match the primitive type names, but just with a capital letter, denoting it as a class. The two exceptions are char / Character and int / Integer. These primitive names are historical, coming from the C programming language, and you'll just need to remember that their primitives have the shortened name and the wrapper class uses the full word name for those two cases. But it probably won't be too hard as you're already familiar with int s and probably won't use char / Character all that often.
Why do they exist?
These wrapper classes offer a few things:
- You can set a wrapper object reference to null, but you cannot set a primitive to null
- Some classes accept only objects, so they cannot accept an int/float/double... (e.g. ArrayList), so to use them, you'll need to use the wrapper classes
- The wrapper classes offer some helpful methods: converting between types, to/from String etc.
Immutability
We may have discussed the concept of immutability--a class whose instances cannot be modified in any way once they are constructed. If you want to "modify" the value/state of an immutable class instance, you'll need to call a method or operation that creates a new instance. This applies to each of these primitive wrapper classes: All primitive wrapper classes are immutable.
Some primitive wrapper methods for conversion
Explicitly converting between primitives, wrappers, String (using int/Integer as an example):
Between primitive/wrapper types:
- int -> Integer: Integer's class method, valueOf(int), converts an int to an Integer:
This is done by Java behind the scenes in:Integer wrapperInteger = Integer.valueOf(22);
Integer wrapperInteger = 22;
- Integer -> int: Integer's instance method, intValue(), converts an Integer to an int:
This is done by Java behind the scenes in:Integer wrapperInteger = new Integer(22); int primitiveInt = wrapperInteger.intValue();
int primitiveInt = wrapperInteger;
From String to different types:
- String -> int: Use Integer's class method, parseInt(String):
int primitiveInt = Integer.parseInt("22");
- String -> Integer: Use valueOf(String):
Integer wrapperInteger = Integer.valueOf("22");
From different types to String:
- int -> String: Use Integer.toString(int):
String intString = Integer.toString(22);
- Integer -> String: Use toString() instance method:
Integer wrapperInteger = Integer.valueOf(22); String integerString = wrapperInteger.toString();
Summary of Conversions:
From Type | To Type | method | Example |
---|---|---|---|
int | Integer | Integer.valueOf(int) | Integer wrapperInteger = Integer.valueOf(22); |
Integer | int | Integer#intValue() | Integer wrapperInteger = new Integer(22); int primitiveInt = wrapperInteger.intValue(); |
String | int | Integer.parseInt(String) | int primitiveInt = Integer.parseInt("22"); |
String | Integer | Integer.valueOf(String) | Integer wrapperInteger = Integer.valueOf("22"); |
int | String | Integer.toString(int) | String intString = Integer.toString(22); |
Integer | String | Integer#toString() | Integer wrapperInteger = Integer.valueOf(22); String integerString = wrapperInteger.toString(); |
There are analogous conversion methods for the other wrapper types. For example, Double.valueOf(double), doublePrimitive.doubleValue()... search google for "Java Double class" or "Java Boolean class" and you should quickly find the javadoc documentation from Oracle on the relevant class.
Lists
Lists are ordered collections that allow duplicate elements. Elements can be accessed by their integer index.
Common List Implementations:
- ArrayList - Resizable array implementation; fast for random access, slower for insertions/deletions
- LinkedList - Doubly-linked list implementation; fast for insertions/deletions, slower for random access
- Vector - Legacy synchronized list implementation (thread-safe)
- Stack - Legacy LIFO (Last-In-First-Out) stack implementation
Example:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// ArrayList example
List arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("JavaScript");
arrayList.add("Java"); // Duplicates allowed
System.out.println("ArrayList: " + arrayList);
System.out.println("Element at index 1: " + arrayList.get(1));
// LinkedList example
List linkedList = new LinkedList<>(arrayList); // Initialize with another collection
linkedList.add(0, "C++"); // Add at specific position
linkedList.remove("Java"); // Remove first occurrence
System.out.println("LinkedList: " + linkedList);
// Common operations
System.out.println("Size: " + linkedList.size());
System.out.println("Contains 'Python'? " + linkedList.contains("Python"));
System.out.println("Index of 'JavaScript': " + linkedList.indexOf("JavaScript"));
}
}
Sets
Sets are collections that cannot contain duplicate elements. They model the mathematical set abstraction.
Common Set Implementations:
- HashSet - Uses hash table for storage; doesn't guarantee order, offers constant-time performance
- LinkedHashSet - Hash table with linked list, maintains insertion order
- TreeSet - Based on TreeMap (Red-Black tree), elements stored in sorted order
Example:
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
public class SetExample {
public static void main(String[] args) {
// HashSet example
Set hashSet = new HashSet<>();
hashSet.add(10);
hashSet.add(5);
hashSet.add(20);
hashSet.add(10); // Duplicate - will be ignored
System.out.println("HashSet: " + hashSet); // Order not guaranteed
// LinkedHashSet example - maintains insertion order
Set linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(10);
linkedHashSet.add(5);
linkedHashSet.add(20);
System.out.println("LinkedHashSet: " + linkedHashSet); // Maintains insertion order
// TreeSet example - maintains sorted order
Set treeSet = new TreeSet<>();
treeSet.add(10);
treeSet.add(5);
treeSet.add(20);
System.out.println("TreeSet: " + treeSet); // Natural ordering (ascending)
// Set operations
Set set1 = new HashSet<>(Set.of(1, 2, 3, 4, 5));
Set set2 = new HashSet<>(Set.of(4, 5, 6, 7, 8));
// Union
Set union = new HashSet<>(set1);
union.addAll(set2);
System.out.println("Union: " + union);
// Intersection
Set intersection = new HashSet<>(set1);
intersection.retainAll(set2);
System.out.println("Intersection: " + intersection);
// Difference
Set difference = new HashSet<>(set1);
difference.removeAll(set2);
System.out.println("Difference (set1 - set2): " + difference);
}
}
Maps
Maps are objects that map keys to values. A map cannot contain duplicate keys, and each key can map to at most one value.
Common Map Implementations:
- HashMap - General-purpose implementation based on a hash table
- LinkedHashMap - Hash table with linked list, maintains insertion order of keys
- TreeMap - Based on a Red-Black tree, keys maintained in sorted order
- Hashtable - Legacy synchronized implementation (thread-safe)
Example:
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapExample {
public static void main(String[] args) {
// HashMap example
Map hashMap = new HashMap<>();
hashMap.put("John", 25);
hashMap.put("Alice", 30);
hashMap.put("Bob", 28);
hashMap.put("John", 26); // Overwrites previous value for "John"
System.out.println("HashMap: " + hashMap); // Order not guaranteed
// LinkedHashMap example - maintains insertion order
Map linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("John", 25);
linkedHashMap.put("Alice", 30);
linkedHashMap.put("Bob", 28);
System.out.println("LinkedHashMap: " + linkedHashMap); // Maintains insertion order
// TreeMap example - maintains sorted key order
Map treeMap = new TreeMap<>();
treeMap.put("John", 25);
treeMap.put("Alice", 30);
treeMap.put("Bob", 28);
System.out.println("TreeMap: " + treeMap); // Sorted by keys
// Common operations
System.out.println("Value for 'Alice': " + hashMap.get("Alice"));
System.out.println("Contains key 'David'? " + hashMap.containsKey("David"));
System.out.println("Contains value 28? " + hashMap.containsValue(28));
// Iterating over a Map
System.out.println("Iterating over HashMap:");
for (Map.Entry entry : hashMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Using forEach (Java 8+)
System.out.println("Using forEach:");
hashMap.forEach((key, value) -> System.out.println(key + ": " + value));
}
}