Java > Core Java > Variables and Data Types > Wrapper Classes

Wrapper Class Demonstration: Integer and Double

This code demonstrates the use of wrapper classes in Java. Wrapper classes are used to represent primitive data types as objects. This example focuses on Integer and Double, wrapping int and double primitives, respectively. It showcases how to create wrapper objects, access their values, and perform basic operations. We'll explore autoboxing and unboxing, and methods for converting strings to wrapper objects.

Code Snippet: Integer and Double Wrapper Usage

This code snippet demonstrates the creation and usage of Integer and Double wrapper classes. It covers the following key aspects:

  1. Object Creation: Creating wrapper objects using new Integer() and new Double() (Deprecated, kept for legacy considerations), but recommended to use Integer.valueOf() and Double.valueOf().
  2. Autoboxing: Automatic conversion from primitive types (int, double) to wrapper objects (Integer, Double). This simplifies the code.
  3. Unboxing: Automatic conversion from wrapper objects (Integer, Double) to primitive types (int, double).
  4. String Conversion: Converting strings to Integer and Double objects using Integer.parseInt(), Double.parseDouble(), Integer.valueOf(), and Double.valueOf(). parseInt() and parseDouble() return primitive types, while valueOf() returns wrapper objects.

public class WrapperExample {
    public static void main(String[] args) {
        // Creating Integer wrapper objects
        Integer intObject1 = new Integer(10); // Deprecated since Java 9, but for compatibility
        Integer intObject2 = Integer.valueOf(20); // Preferred method

        // Creating Double wrapper objects
        Double doubleObject1 = new Double(3.14); // Deprecated since Java 9, but for compatibility
        Double doubleObject2 = Double.valueOf(2.71828);

        // Autoboxing (automatic conversion from int to Integer and double to Double)
        Integer intObject3 = 30;
        Double doubleObject3 = 1.618;

        // Unboxing (automatic conversion from Integer to int and Double to double)
        int intValue = intObject1.intValue();
        double doubleValue = doubleObject1.doubleValue();

        // Printing values
        System.out.println("Integer Object 1: " + intObject1);
        System.out.println("Integer Object 2: " + intObject2);
        System.out.println("Integer Object 3 (Autoboxed): " + intObject3);
        System.out.println("Double Object 1: " + doubleObject1);
        System.out.println("Double Object 2: " + doubleObject2);
        System.out.println("Double Object 3 (Autoboxed): " + doubleObject3);
        System.out.println("int Value (Unboxed from intObject1): " + intValue);
        System.out.println("double Value (Unboxed from doubleObject1): " + doubleValue);

        // String to Integer and Double
        String intString = "123";
        String doubleString = "4.56";

        Integer parsedInt = Integer.parseInt(intString); // Returns primitive int
        Double parsedDouble = Double.parseDouble(doubleString); // Returns primitive double

        Integer parsedIntObject = Integer.valueOf(intString); // Returns Integer Object
        Double parsedDoubleObject = Double.valueOf(doubleString); // Returns Double Object

        System.out.println("Parsed Integer from String: " + parsedInt); 
        System.out.println("Parsed Double from String: " + parsedDouble);  
        System.out.println("Parsed Integer Object from String: " + parsedIntObject); 
        System.out.println("Parsed Double Object from String: " + parsedDoubleObject); 

    }
}

Concepts Behind the Snippet

Wrapper classes serve two primary purposes:

  1. Object Representation: To represent primitive data types as objects. This is necessary when you need to use primitives in contexts that require objects (e.g., collections).
  2. Utility Methods: To provide utility methods for working with primitive data types, such as parsing strings to numbers, converting between number systems, and more.
Autoboxing and unboxing are important features introduced in Java 5 that simplify the use of wrapper classes by automatically converting between primitives and their corresponding wrapper objects.

Real-Life Use Case

Consider a scenario where you need to store a list of integers, but the List interface only accepts objects. You can use the Integer wrapper class to store the integers as objects in the list. Another common use case is when reading data from a file or database where numbers might be represented as strings. Wrapper classes provide methods to parse these strings into numerical values.

import java.util.ArrayList;
import java.util.List;

public class WrapperListExample {
    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<>();
        integerList.add(Integer.valueOf(10));
        integerList.add(20); // Autoboxing
        integerList.add(Integer.valueOf(30));

        int sum = 0;
        for (Integer i : integerList) {
            sum += i; // Unboxing
        }

        System.out.println("Sum of integers: " + sum);
    }
}

Best Practices

  • Use Integer.valueOf() and Double.valueOf(): Instead of the constructor (new Integer()), use the static factory methods Integer.valueOf() and Double.valueOf() for better performance, as they can reuse existing objects in the cache for frequently used values.
  • Null Checks: When dealing with wrapper objects that might be null, perform null checks before unboxing to avoid NullPointerException.

Interview Tip

Be prepared to explain the difference between primitive data types and wrapper classes, the concepts of autoboxing and unboxing, and the advantages of using wrapper classes in certain situations. Understand the potential for NullPointerException when unboxing a null wrapper object.

When to Use Them

Use wrapper classes when:

  1. You need to store primitive data types in collections (e.g., List, Set, Map).
  2. You need to represent a value that might be absent (e.g., using null to indicate no value).
  3. You need to use utility methods provided by wrapper classes (e.g., parsing strings, converting between number systems).

Memory Footprint

Wrapper objects consume more memory than their primitive counterparts. An int takes 4 bytes, while an Integer object typically takes 16 bytes or more due to object overhead. Be mindful of this when dealing with large datasets.

Alternatives

In some situations, you might be able to use primitive arrays instead of collections of wrapper objects if you don't need the flexibility of collections and are concerned about memory usage. Libraries like Trove4j provides high performance primitive collections.

Pros

  • Allow primitive types to be treated as objects.
  • Provide utility methods for primitive type manipulation.
  • Enable the use of generics with primitive types.

Cons

  • Increased memory consumption compared to primitive types.
  • Potential for NullPointerException during unboxing.
  • Performance overhead due to object creation and unboxing.

FAQ

  • What is autoboxing?

    Autoboxing is the automatic conversion of a primitive data type (e.g., int) into its corresponding wrapper class object (e.g., Integer).
  • What is unboxing?

    Unboxing is the automatic conversion of a wrapper class object (e.g., Integer) into its corresponding primitive data type (e.g., int).
  • Why use Integer.valueOf() instead of new Integer()?

    Integer.valueOf() can reuse existing Integer objects from a cache for commonly used values (typically -128 to 127), which can improve performance. new Integer() always creates a new object.
  • What happens if I try to unbox a null Integer?

    You will get a NullPointerException at runtime. Always check for null before unboxing.