GFG Day 13: Wrapper Classes and Static Members

sri parthusri parthu
8 min read

Wrapper Classes in Java

  • In Java, wrapper classes are used to wrap primitive data types into objects. When an object is created in a wrapper class, it has a field that can hold primitive data types. Let's check on the wrapper classes in Java with examples.
Primitive TypeWrapper Class
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

Why Wrapper Classes?

  • Java is object-oriented but primitive types (like int, char) are not objects. To treat them as objects (e.g., storing them in collections), we need wrapper classes.

Example to demonstrate converting a primitive to its corresponding wrapper.

public class WrapperDemo
{
    public static void main(String[] args)
    {
        // Primitive data type
        int b;

        // Integer wrapper class
        Integer a;

        // assigning value to primitive 
        b = 357;

        // auto-boxing or auto wrapping converting primitive int to Integer object
        a = b; 

        System.out.println("The primitive int b is: " + b);
        System.out.println("The Integer object a is: " + a);
    }
}

Output

The primitive int b is: 357
The Integer object a is: 357

Explanation: In the above example, we first create a primitive int b and assign it a value of 357. Then we assign this primitive value to an Integer object a, and it automatically converts from a primitive to an Integer object (autoboxing).

Need of Wrapper Classes

  • The following are requirements for using Java's wrapper class:

    • Objects are created from primitive data types. If we want to change the arguments that are passed into a method, because primitive types are passed by value.

    • Wrapper classes are useful in this situation because the classes in the java.util package only handle objects.

    • Only objects (reference types), not primitive types, are stored in data structures like ArrayList and Vector that are part of the Collection framework.

    • An object is needed to support synchronization in multithreading.

Below are examples of wrapper classes in Java with their corresponding primitive data types in Java.

Autoboxing and Unboxing

1. Autoboxing

  • Autoboxing is the process of automatically converting primitive types to the object of their corresponding wrapper classes. For example, conversion of int to Integer, long to Long, double to Double, etc.

Example of a Java program to demonstrate the automatic conversion of a primitive to a wrapper class (autoboxing).

import java.util.ArrayList;

public class AutoBoxingWrapper
{
    public static void main(String[] args)
    {
        char ch = 'a';

        // Autoboxing- primitive to Character object
        // conversion
        Character a = ch;

        ArrayList<Integer> arrayList
            = new ArrayList<Integer>();

        // Autoboxing because ArrayList stores only objects
        arrayList.add(25);

        // printing the values from object
        System.out.println(arrayList.get(0));
    }
}

Output

25

2. Unboxing

  • It is just the reverse process of autoboxing. Unboxing is the process of automatically converting an object of a wrapper class into its corresponding primitive type. For example, conversion of Integer to int, Long to long, Double to double, etc.

An example of a Java program demonstrates the automatic conversion of a wrapper class to a primitive (unboxing).

import java.util.ArrayList;

public class UnboxingWrapper
{
    public static void main(String[] args)
    {
        Character ch = 'a';

        // unboxing - Character object to primitive conversion
        char a = ch;

        ArrayList<Integer> arrayList
            = new ArrayList<Integer>();
        arrayList.add(24);

        // unboxing because get method returns an Integer object
        int num = arrayList.get(0);

        // printing the values from primitive data types
        System.out.println(num);
    }
}

Output

24

Java Wrapper Classes Example

import java.io.*;

public class Wrapper {
    public static void main(String[] args)
    {
        // byte data type
        byte a = 1;

        // wrapping around Byte object (use valueOf or autoboxing)
        Byte byteobj = Byte.valueOf(a);

        // int data type
        int b = 10;

        // wrapping around Integer object (use valueOf or autoboxing)
        Integer intobj = Integer.valueOf(b);

        // float data type
        float c = 18.6f;

        // wrapping around Float object (use valueOf or autoboxing)
        Float floatobj = Float.valueOf(c);

        // double data type
        double d = 250.5;

        // Wrapping around Double object (use valueOf or autoboxing)
        Double doubleobj = Double.valueOf(d);

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

        // wrapping around Character object (autoboxing)
        Character charobj = e;

        // printing the values from objects
        System.out.println(
            "Values of Wrapper objects (printing as objects)");
        System.out.println("\nByte object byteobj: "
                           + byteobj);
        System.out.println("\nInteger object intobj: "
                           + intobj);
        System.out.println("\nFloat object floatobj: "
                           + floatobj);
        System.out.println("\nDouble object doubleobj: "
                           + doubleobj);
        System.out.println("\nCharacter object charobj: "
                           + charobj);

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

        // printing the values from data types
        System.out.println(
            "\nUnwrapped values (printing as data types)");
        System.out.println("\nbyte value, bv: " + bv);
        System.out.println("\nint value, iv: " + iv);
        System.out.println("\nfloat value, fv: " + fv);
        System.out.println("\ndouble value, dv: " + dv);
        System.out.println("\nchar value, cv: " + cv);
    }
}

Output

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

Custom Wrapper Classes in Java

  • Primitive data types are wrapped by Java Wrapper classes. Data can be wrapped inside a class that we construct. Let's now examine how to construct a custom wrapper class in Java. It can be used to create certain structures, such as stacks, queues, etc.

Example

import java.io.*;

// wrapper class
class Maximum {
    private int maxi = 0;
    private int size = 0;

    public void insert(int x)
    {
        this.size++;
        if (x <= this.maxi)
            return;
        this.maxi = x;
    }

    public int top() { return this.maxi; }

    public int elementNumber() { return this.size; }
};

class CustomWrapper {
    public static void main(String[] args)
    {
        Maximum x = new Maximum();
        x.insert(12);
        x.insert(3);
        x.insert(23);

        System.out.println("Maximum element: " + x.top());
        System.out.println("Number of elements inserted: "
                           + x.elementNumber());
    }
}

Output

Maximum element: 23
Number of elements inserted: 3

Advantages of Wrapper Classes

  • Collections allow only object data.

  • On object data we can call multiple methods: compareTo(), equals(), toString()

  • The cloning process only works on objects

  • Object data allows null values.

  • Serialization allows only object data.


Static Blocks in Java

What is a static block?

  • A static block in Java is a block of code that runs only once when the class is loaded into memory, before the main() method or any static methods or fields are accessed. It is also known as a static initialization block.

Calling of static block in Java?

  • In order to call any static block, there is no specified way, as a static block executes automatically when the class is loaded in memory.

Illustration:

public class StaticBlock {

        // Constructor of this class
        GFG() {}

        // Method of this class
        public static void print() { }

        static{}

        public static void main(String[] args) {

                // Calling of method inside main()
                StaticBlock obj = new StaticBlock ();

                // Calling of constructor inside main()
                new StaticBlock ();

                // Calling of static block
                // Nothing to do here as it is called
                // automatically as class is loaded in memory

        }
}

Note: From the above illustration, we can perceive that static blocks are automatically called as soon as the class is loaded in memory, and there is nothing to do as we have to in case of calling methods and constructors inside main().

Can we print something on the console without creating a main() method?

  • The question is important from the point of view of the interview. The answer is that if we are using JDK version 1.6 or earlier, we can print; if not, an error will be thrown.

Example 1-A: Running on JDK version 1.6 of the Previous

public class StaticBlock {

    // Static block
    static
    {
        // Print statement
        System.out.print(
            "Static block can be printed without main method");
    }
}

Output

Static block can be printed without the main method

Example 1-B: Running on JDK version 1.6 and later

public class StaticBlock {

    // Static block
    static
    {
        // Print statement
        System.out.print(
            "Static block can be printed without main method");
    }
}

Output

Error: Main method not found in class StaticBlock, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

Execution of Static Block

Example 1:

  • Executing static blocks before constructors.
class Test {

    // Case 1: Static variable
    static int i;
    // Case 2: non-static variables
    int j;

    // Case 3: Static block
    static
    {
        i = 10;
        System.out.println("static block called ");
    }
    // End of static block
}

// Class 2
public class StaticExecution {

    // Main driver method
    public static void main(String args[])
    {
        System.out.println(Test.i);
    }
}

Output

static block called 
10

Example 2:

class Test {

    // Case 1: Static variable
    static int i;
    // Case 2: Non-static variable
    int j;

    // Case 3: Static blocks
    static
    {
        i = 10;
        System.out.println("static block called ");
    }

    // Constructor calling
    Test() { System.out.println("Constructor called"); }
}

class StaticExecution {

    // Main driver method
    public static void main(String args[])
    {

        // Although we have two objects, static block is executed only once.
        Test t1 = new Test();
        Test t2 = new Test();
    }
}

Output

static block called 
Constructor called
Constructor called
  • Static initialization blocks may appear anywhere in the class body and in any number of classes. Static initialization blocks are guaranteed to be called in the order they occur in the source code by the runtime system.

Note: In Java, we use an Initializer Block if we want to run a piece of code for each object. This is a common practice in developing industry sectors.


Happy Learning

Thanks For Reading! :)

SriParthu ๐Ÿ’๐Ÿ’ฅ

0
Subscribe to my newsletter

Read articles from sri parthu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

sri parthu
sri parthu

Hello! I'm Sri Parthu! ๐ŸŒŸ I'm aiming to be a DevOps & Cloud enthusiast ๐Ÿš€ Currently, I'm studying for a BA at Dr. Ambedkar Open University ๐Ÿ“š I really love changing how IT works to make it better ๐Ÿ’ก Let's connect and learn together! ๐ŸŒˆ๐Ÿ‘‹