Home » Java Wrapper Classes Tutorial

Java Wrapper Classes Tutorial

In Java, wrapper classes are used to represent primitive data types as objects. Every primitive data type in Java has a corresponding wrapper class in the java.lang package.

Wrapper classes allow primitives to be used as objects when necessary, such as when working with collections (like ArrayList) or generics.

Wrapper classes provide methods to perform operations on primitive types, such as parsing, conversion, and null handling, which cannot be done with the primitives directly.

In this tutorial, we'll explore Java's wrapper classes with several code examples to demonstrate how they are used and how they convert between primitive types and objects.

1. List of Java Wrapper Classes

Java provides the following wrapper classes for each primitive data type:

Primitive Type Wrapper Class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

2. Why Use Wrapper Classes?

Wrapper classes are useful in many scenarios:

Collections: Java collections (like ArrayList) only work with objects, so primitive types need to be wrapped in their corresponding wrapper classes.
Type conversion: Wrapper classes provide utility methods for converting between different data types (e.g., parsing strings into numbers).
Null handling: Unlike primitive types, wrapper classes can store null values, which are useful in certain contexts.
Autoboxing and Unboxing: Java automatically converts between primitives and wrapper objects (autoboxing/unboxing), making the code easier to read and write.

3. Creating Wrapper Objects (Boxing)

Wrapper objects can be created in two ways:

Using the constructor of the wrapper class.
Using static factory methods (e.g., valueOf()).

Example: Creating Wrapper Objects

public class WrapperExample {
    public static void main(String[] args) {
        // Creating wrapper objects using constructor (Deprecated in newer versions)
        Integer intObj1 = new Integer(100);  // Deprecated in Java 9
        Double doubleObj1 = new Double(5.5); // Deprecated in Java 9

        // Creating wrapper objects using valueOf() (Preferred method)
        Integer intObj2 = Integer.valueOf(200);
        Double doubleObj2 = Double.valueOf(10.5);

        // Displaying the values
        System.out.println("intObj1: " + intObj1);
        System.out.println("doubleObj1: " + doubleObj1);
        System.out.println("intObj2: " + intObj2);
        System.out.println("doubleObj2: " + doubleObj2);
    }
}

Explanation:

You can create wrapper objects using the constructor (deprecated in newer versions) or the preferred valueOf() method.
Wrapper objects represent the corresponding primitive values.

Output:

intObj1: 100
doubleObj1: 5.5
intObj2: 200
doubleObj2: 10.5

4. Autoboxing and Unboxing

Autoboxing is the automatic conversion of a primitive type into its corresponding wrapper class object. Unboxing is the reverse process: converting a wrapper object back into a primitive type. Java automatically performs these conversions when needed, making the code more concise.

Example: Autoboxing and Unboxing

public class AutoboxingUnboxingExample {
    public static void main(String[] args) {
        // Autoboxing: converting a primitive to a wrapper object
        Integer intObj = 10;  // Equivalent to Integer.valueOf(10)

        // Unboxing: converting a wrapper object to a primitive
        int intValue = intObj;  // Equivalent to intObj.intValue()

        // Displaying the values
        System.out.println("Wrapper object (Integer): " + intObj);
        System.out.println("Primitive value (int): " + intValue);
    }
}

Explanation:

Java automatically converts int to Integer (autoboxing) and Integer to int (unboxing).
This feature makes code easier to read by reducing explicit conversions.

Output:

Wrapper object (Integer): 10
Primitive value (int): 10

5. Wrapper Class Methods

Each wrapper class provides several utility methods for manipulating and converting primitive values. Some common methods include:

parse(): Converts a String into a primitive type.
valueOf(): Converts a String or primitive into a wrapper object.
Value(): Converts the wrapper object to a primitive.

Example: Common Wrapper Class Methods

public class WrapperMethodsExample {
    public static void main(String[] args) {
        // Using parse methods to convert String to primitive types
        int intValue = Integer.parseInt("123");
        double doubleValue = Double.parseDouble("45.67");

        // Using valueOf() to create wrapper objects from strings
        Integer intObj = Integer.valueOf("100");
        Double doubleObj = Double.valueOf("99.99");

        // Converting wrapper objects to primitive types
        int primitiveInt = intObj.intValue();
        double primitiveDouble = doubleObj.doubleValue();

        // Displaying results
        System.out.println("Parsed int: " + intValue);
        System.out.println("Parsed double: " + doubleValue);
        System.out.println("Wrapper Integer object: " + intObj);
        System.out.println("Wrapper Double object: " + doubleObj);
        System.out.println("Primitive int from Integer object: " + primitiveInt);
        System.out.println("Primitive double from Double object: " + primitiveDouble);
    }
}

Explanation:

parseInt() and parseDouble() are used to convert String values to int and double primitives, respectively.
valueOf() is used to create wrapper objects from String values.
Value() methods are used to retrieve the primitive value from wrapper objects.

Output:

Parsed int: 123
Parsed double: 45.67
Wrapper Integer object: 100
Wrapper Double object: 99.99
Primitive int from Integer object: 100
Primitive double from Double object: 99.99

6. Wrapper Classes in Collections

Java collections (such as ArrayList, HashMap, etc.) cannot store primitive types directly. Instead, wrapper classes are used to store primitive values as objects in collections.

Example: Using Wrapper Classes in Collections

import java.util.ArrayList;

public class WrapperInCollectionsExample {
    public static void main(String[] args) {
        // Creating an ArrayList to store Integer objects (autoboxing will occur)
        ArrayList intList = new ArrayList<>();

        // Adding primitive int values (autoboxing to Integer objects)
        intList.add(10);  // Autoboxing converts int to Integer
        intList.add(20);
        intList.add(30);

        // Retrieving and using the values (unboxing to int)
        int sum = 0;
        for (Integer num : intList) {
            sum += num;  // Unboxing converts Integer to int
        }

        // Displaying the sum
        System.out.println("Sum: " + sum);
    }
}

Explanation:

The ArrayList stores Integer objects (not primitive int).
Autoboxing automatically converts the primitive int values into Integer objects when added to the list, and unboxing occurs when they are retrieved.

Output:

Sum: 60

7. Null Handling with Wrapper Classes

One key advantage of wrapper classes is their ability to store null values, unlike primitive types which cannot hold null. This is useful in scenarios where a value may not be present.

Example: Null Handling with Wrapper Classes

public class NullHandlingExample {
    public static void main(String[] args) {
        // Integer can hold null, but int cannot
        Integer nullableInt = null;

        // Trying to use int with null will cause NullPointerException
        try {
            int primitiveInt = nullableInt;  // Unboxing a null value will throw an exception
        } catch (NullPointerException e) {
            System.out.println("Caught NullPointerException when unboxing null Integer");
        }

        // Safe check for null before unboxing
        if (nullableInt != null) {
            int safeInt = nullableInt;  // Only unbox if not null
            System.out.println("Safe int value: " + safeInt);
        } else {
            System.out.println("No value present");
        }
    }
}

Explanation:

Wrapper classes can hold null values, unlike primitive types.
Unboxing a null value will cause a NullPointerException, so it's important to check for null before unboxing.

Output:

Caught NullPointerException when unboxing null Integer
No value present

8. Performance Considerations

While wrapper classes provide additional functionality, they come with some performance overhead compared to primitive types:

Memory Usage: Wrapper objects consume more memory than primitive types.
Autoboxing/Unboxing: Implicit conversions between primitives and wrapper objects can introduce performance costs.
Null Handling: Wrapper classes are nullable, which adds flexibility but also the risk of NullPointerException.
When performance is critical (e.g., in loops), consider using primitive types to avoid the overhead of autoboxing/unboxing.

Example: Performance Impact of Autoboxing

public class AutoboxingPerformanceExample {
    public static void main(String[] args) {
        long startTime, endTime;

        // Using primitive int
        startTime = System.nanoTime();
        int sum1 = 0;
        for (int i = 0; i < 1000000; i++) {
            sum1 += i;
        }
        endTime = System.nanoTime();
        System.out.println("Time with int: " + (endTime - startTime) + " ns");

        // Using wrapper Integer (autoboxing/unboxing)
        startTime = System.nanoTime();
        Integer sum2 = 0;
        for (int i = 0; i < 1000000; i++) {
            sum2 += i;  // Autoboxing/unboxing occurs
        }
        endTime = System.nanoTime();
        System.out.println("Time with Integer: " + (endTime - startTime) + " ns");
    }
}

Explanation:

The loop that uses int performs faster than the one that uses Integer because of the overhead of autoboxing/unboxing.

Sample Output:

Time with int: 116499 ns
Time with Integer: 3538675 ns

Conclusion

Java wrapper classes are a powerful tool that allows you to treat primitive data types as objects. They provide utility methods for parsing, converting, and manipulating primitive data, and are essential for working with Java collections and generics.

Key Points:

Wrapper Classes: Each primitive type has a corresponding wrapper class (int → Integer, char → Character, etc.).
Autoboxing and Unboxing: Java automatically converts between primitives and wrapper objects.
Utility Methods: Wrapper classes provide methods like valueOf(), parse(), and Value() for conversion and manipulation.
Null Handling: Unlike primitive types, wrapper classes can store null values.
Collections: Java collections can only hold objects, so wrapper classes are used to store primitive values.
Performance Considerations: While convenient, wrapper classes can introduce performance overhead due to memory usage and autoboxing/unboxing.

By understanding and using wrapper classes effectively, you can write more flexible and object-oriented code in Java.

You may also like