Using wrapper classes in Java


Reading time: 30 minutes

A Wrapper class is a class whose object contains a primitive data types. We can think this as a primitive data type with an additional layer which enables it is get benefits of a custom user defined objects in Java.

Why we need Wrapper Classes?

  1. Methods cannot modify data of primitive data types which have been passed an arguments. To do this, we need to use a wrapper class over the primitive data type.

  2. The classes in java.util package handles only objects and hence wrapper classes help in converting primitive types to objects and hence, use the utilities

  3. Data structures in the Collection framework, such as ArrayList and Vector, store only objects and not primitive types.

  4. Only an object can support synchronization in multithreading.

Syntax

Consider a class named prev_class which can be a primitive datatype like int as well. To wrap it in a wrapper class, we create a new class with any valid name like new_class like:

class new_class
{
    prev_class variable;
    
    return_type some_functions()
    {
        ...
    }
}

Example of wrapping an int:

class int_wrapper
{
    int data;
    void set_data(int new_data)
    {
        data = new_data;
    }
}

Following this, we can create objects and set new data like:

int_wrapper int_object();
int_object.data = 1;
int_object.set_data(2);

In-built wrapper classes

The seven classes of java.lang package are known as wrapper classes in java. The list of seven wrapper classes are given below:

  • Primitive type boolean -> Wrapper class Boolean
Primitive datatype Wrapper class
boolean Boolean
char Character
byte Byte
short Short
int Integer
long Long
float Float
double Double

Autoboxing and Unboxing

As we know, Java automatically converts between datatypes to minimize the loss in accuracy. In this process, we have different rules for conversion of supported wrapper classes like Integer.

The two type of conversions are:

  • Autoboxing
  • Unboxing

Autoboxing:

Automatic conversion of primitive types to the object of their corresponding wrapper classes is known as autoboxing. For example – conversion of int to Integer, long to Long, double to Double etc.

Example:

// Java program to demonstrate Autoboxing 
public class WrapperExample1{  
    public static void main(String args[]){  
    //Converting int into Integer  
    int a=21;  
    Integer i=Integer.valueOf(a);//converting int into Integer  
    Integer j=a;//autoboxing, now compiler will write Integer.valueOf(a) internally  

    System.out.println(a+" "+i+" "+j);  
    }
}  

Output:

21 21 21

Unboxing: It is just the reverse process of autoboxing. Automatically converting an object of a wrapper class to its corresponding primitive type is known as unboxing. For example – conversion of Integer to int, Long to long, Double to double etc.

// Java program to demonstrate Unboxing 
public class WrapperExample2{    
    public static void main(String args[]){    
    //Converting Integer to int    
    Integer a=new Integer(5);    
    int i=a.intValue();//converting Integer to int  
    int j=a;//unboxing, now compiler will write a.intValue() internally    
    System.out.println(a+" "+i+" "+j);    
    }
}    

Output:

5 5 5

Implemetation

Following implementation demonstrates autoboxing and unboxing:

// Java program to demonstrate Wrapping and UnWrapping 
// in Java Classes 
class AutoBoxingUnBoxing 
{ 
	public static void main(String args[]) 
	{ 
		// byte data type 
		byte a = 1; 

		// wrapping around Byte object 
		Byte byteobj = new Byte(a); 

		// int data type 
		int b = 11; 

		//wrapping around Integer object 
		Integer intobj = new Integer(b); 

		// float data type 
		float c = 11.6f; 

		// wrapping around Float object 
		Float floatobj = new Float(c); 

		// double data type 
		double d = 251.5; 

		// Wrapping around Double object 
		Double doubleobj = new Double(d); 

		// char data type 
		char e='a'; 

		// wrapping around Character object 
		Character charobj=e; 

		// printing the values from objects 
		System.out.println("Values of Wrapper objects (printing as objects)"); 
		System.out.println("Byte object byteobj: " + byteobj); 
		System.out.println("Integer object intobj: " + intobj); 
		System.out.println("Float object floatobj: " + floatobj); 
		System.out.println("Double object doubleobj: " + doubleobj); 
		System.out.println("Character object charobj: " + charobj); 

		// objects to data types (retrieving data types from objects) 
		// unwrapping objects to primitive data types 
		byte bv = byteobj; 
		int iv = intobj; 
		float fv = floatobj; 
		double dv = doubleobj; 
		char cv = charobj; 

		// printing the values from data types 
		System.out.println("Unwrapped values (printing as data types)"); 
		System.out.println("byte value, bv: " + bv); 
		System.out.println("int value, iv: " + iv); 
		System.out.println("float value, fv: " + fv); 
		System.out.println("double value, dv: " + dv); 
		System.out.println("char value, cv: " + cv); 
	} 
} 

Output:

Values of Wrapper objects (printing as objects)
Byte object byteobj:  1
Integer object intobj:  11
Float object floatobj:  11.6
Double object doubleobj:  251.5
Character object charobj: a
Unwrapped values (printing as data types)
byte value, bv: 1
int value, iv: 11
float value, fv: 11.6
double value, dv: 251.5
char value, cv: a

Using with Collection Objects

Sometimes you must use wrapper classes, for example when working with Collection objects, such as ArrayList, where primitive types cannot be used (the list can only store objects):

Example:

ArrayList<int> myNumbers = new ArrayList<int>(); // Invalid
ArrayList<Integer> myNumbers = new ArrayList<Integer>(); // Valid

Utility Methods of Wrapper Classes

Since you're now working with objects, you can use certain methods to get information about the specific object.

For example, the following methods are used to get the value associated with the corresponding wrapper object: intValue(), byteValue(), shortValue(), longValue(), floatValue(), doubleValue(), charValue(), booleanValue().

This example will output the same result as the example above:

public class MyClass 
{ 
  public static void main(String[] args) 
  { 
    Integer myInt = 5; 
    Double myDouble = 5.99; 
    Character myChar = 'A'; 
    System.out.println(myInt.intValue());
    System.out.println(myDouble.doubleValue());
    System.out.println(myChar.charValue());
  }
}

Another useful method is the toString() method, which is used to convert wrapper objects to strings.

In the following example, we convert an Integer to a String, and use the length() method of the String class to output the length of the "string":

public class MyClass 
{ 
  public static void main(String[] args) 
  { 
    Integer myInt = 100; 
    String myString = myInt.toString();
    System.out.println(myString.length());
  }
}

Primitive Wrapper Classes are Immutable in Java

Consider below Java program.

// Java program to demonstrate that prmitive 
// wrapper classes are immutable 
class Wrapper 
{ 
	public static void main(String[] args) 
	{ 
		Integer i = new Integer(14); 
		System.out.println(i); 
		modify(i); 
		System.out.println(i); 
	} 

	private static void modify(Integer i) 
	{ 
		i = i + 1; 
	} 
} 

Output:

14
14

The parameter i is reference in modify and refers to same object as i in main(), but changes made to i are not reflected in main(), why?

Explanation:

All primitive wrapper classes (Integer, Byte, Long, Float, Double, Character, Boolean and Short) are immutable in Java, so operations like addition and subtraction create a new object and not modify the old.

The below line of code in the modify method is operating on wrapper class Integer, not an int

i = i + 1;

It does the following:

  • Unwrapping i to an int value
  • Add 1 to that value
  • Wrapping the result into another Integer object
  • Assign the resulting Integer to i

Since object references are passed by value, the action taken in the modify method does not change i that was used as an argument in the call to modify. Thus the main routine still prints 14 after the method returns.

Comparison of Autoboxed Integer objects

When we assign an integer value to an Integer object, the value is autoboxed into an Integer object. For example the statement “Integer x = 1” creates an object ‘x’ with value 1.

Following are some interesting output questions based on comparison of Autoboxed Integer objects.

Predict the output of following Java Program

public class Main 
{ 
	public static void main(String args[]) 
    { 
		Integer x = 200, y = 200; 
		if (x == y) 
			System.out.println("Equal"); 
		else
			System.out.println("Not Equal"); 
	} 
} 

Output:

Not Equal

Since x and y refer to different objects, we get the output as “Not Equal”

The output of following program is a surprise from Java.

public class Main 
{ 
	public static void main(String args[]) 
    { 
		Integer x = 4, y = 4; 
		if (x == y) 
			System.out.println("Equal"); 
		else
			System.out.println("Not Equal"); 
	} 
} 

Output:

Equal

In Java, values from -128 to 127 are cached, so the same objects are returned. The implementation of valueOf() uses cached objects if the value is between -128 to 127.

If we explicitly create Integer objects using new operator, we get the output as “Not Same”. See the following Java program. In the following program, valueOf() is not used.

public class Main 
{ 
	public static void main(String args[]) 
    { 
		Integer x = new Integer(4), y = new Integer(4); 
		if (x == y) 
			System.out.println("Equal"); 
		else
			System.out.println("Not Equal"); 
	} 
} 

Output:

Not Equal

Predict the output of the following program.

Public class Main
{ 
	public static void main(String[] args) 
	{ 
	Integer X = new Integer(1); 
	Integer Y = 1; 

	// Due to auto-boxing, a new Wrapper object 
	// is created which is pointed by Y 
	System.out.println(X == Y); 
	} 
} 

Output:

false

Explanation: Two objects will be created here. First object which is pointed by X due to calling of new operator and second object will be created because of Auto-boxing.