Course Content
Core Java
About Lesson

Ways to create objects

  1. Using new keyword
  2. Using Class.newInstance() method
  3. Using clone() method
  4. Using deserialization
  5. Using newInstance() method of Constructor class

Using new keyword

It is the most common way to create object. It allocates memory for a new object and invokes the constructor to initialize object.

Syntax

ClassName objectName = new ClassName(parameters);

public class Car {
    String model;
    int year;

    // Constructor
    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }

    public void displayInfo() {
        System.out.println("Model: " + model + ", Year: " + year);
    }

    public static void main(String[] args) {
        Car car1 = new Car("Toyota", 2021); // Creating an object
        car1.displayInfo(); // Output: Model: Toyota, Year: 2021
    }
}

Using Class.newInstace() method

In Java, the Class class provides a method called newInstance() that can be used to create new instances of classes dynamically at runtime.

The newInstance() method creates a new instance of the class represented by the Class object on which it is called. It invokes the class’s no-argument constructor to initialize the object.

The class for which you want to create an instance using newInstance() must have a public, no-argument constructor. If the class does not have such a constructor, InstantiationException is thrown.

public class MyClass {
    private String name;

    // Default constructor
    public MyClass() {
        this.name = "Default";
    }

    // Parameterized constructor
    public MyClass(String name) {
        this.name = name;
    }

    // Getter method
    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        try {
            // Obtain the Class object for MyClass
            Class<MyClass> clazz = MyClass.class;

            // Create a new instance of MyClass using newInstance() method
            MyClass obj1 = clazz.newInstance();
            MyClass obj2 = clazz.newInstance();

            // Display the names of the created objects
            System.out.println("Name of obj1: " + obj1.getName());
            System.out.println("Name of obj2: " + obj2.getName());

            // Creating object with parameterized constructor using newInstance() method
            MyClass obj3 = clazz.getDeclaredConstructor(String.class).newInstance("Custom Name");
            System.out.println("Name of obj3: " + obj3.getName());

        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

Using clone() keyword

In Java, cloning is a process of creating an exact copy of an existing object. The clone() method in Java is used to create a duplicate of an object, which is a field-by-field copy of the original object. This method is part of the Cloneable interface and is defined in the Object class.

The Cloneable interface is a marker interface, which means it does not contain any methods. It indicates that a class is eligible for cloning using the clone() method. If a class does not implement Cloneable and its clone() method is called, a CloneNotSupportedException is thrown.

public class Employee implements Cloneable {
    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) {
        try {
            Employee emp1 = new Employee("John", 25);
            Employee emp2 = (Employee) emp1.clone(); // Creating a clone
            System.out.println(emp1.name + ", " + emp1.age); // Output: John, 25
            System.out.println(emp2.name + ", " + emp2.age); // Output: John, 25
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

Types of Cloning

  1. Shallow Cloning: Above code is an example of shallow cloning. It means, clone() will create a new instance of the object but for fields that are objects (references) only the reference is copies not the new object is created. Use shallow cloning when the object contains primitive fields or immutable objects.
  2. Deep Cloning: Creates a new instance of the object and recursively copies all objects referenced by the fields. For fields that are objects, new instances of those objects are created, ensuring that changes to the clone do not affect the original. It is used when the object contains mutable fields or complex objects. This is achieved by adding the code in the overriding clone()method.
public class Address implements Cloneable {
    private String city;

    public Address(String city) {
        this.city = city;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Address{city='" + city + "'}";
    }
}

public class Person implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone(); // Deep clone the address
        return cloned;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "', address=" + address + '}';
    }

    public static void main(String[] args) {
        try {
            Address address = new Address("New York");
            Person original = new Person("John Doe", 30, address);
            Person clone = (Person) original.clone();

            System.out.println("Original: " + original);
            System.out.println("Clone: " + clone);

            // Modifying the clone's address
            clone.address.city = "San Francisco";

            System.out.println("After modifying clone's address:");
            System.out.println("Original: " + original);
            System.out.println("Clone: " + clone);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

Using deserialization

Deserialization is the process of converting a byte stream back into a copy of an object. This is typically used in conjunction with serialization, where the object’s state is saved to a byte stream and later restored. Serialization converts an object into a sequence of bytes that can be easily persisted to a file or sent over a network.

To make a class serializable, it must implement the Serializable interface. This is a marker interface (an interface with no methods) that enables the serialization mechanism to identify objects of this class as serializable.

By implementing the Serializable interface and using ObjectOutputStream and ObjectInputStream, you can serialize and deserialize objects efficiently.

import java.io.*;

public class Person implements Serializable {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        try {
            // Serialization
            Person person = new Person("Alice", 30);
            FileOutputStream fileOut = new FileOutputStream("person.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();

            // Deserialization
            FileInputStream fileIn = new FileInputStream("person.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            Person deserializedPerson = (Person) in.readObject();
            in.close();
            fileIn.close();

            System.out.println("Deserialized Person: " + deserializedPerson.name + ", " + deserializedPerson.age);
            // Output: Deserialized Person: Alice, 30
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Using newInstance method of Constructor class

In Java, reflection provides the ability to inspect and manipulate classes, methods, and fields at runtime. One powerful feature of reflection is the ability to create objects dynamically. The Constructor class, part of the java.lang.reflect package, allows you to create instances of classes using the newInstance() method.

The Constructor class provides information about, and access to, a constructor for a class. It has methods to access the constructor’s metadata, parameters, and to create new instances.

To obtain a Constructor object, you use the getConstructor() or getDeclaredConstructor() methods from the Class object. The getConstructor() method retrieves public constructors, while getDeclaredConstructor() retrieves all constructors regardless of their access modifier.

The newInstance() method of the Constructor class creates a new instance of the class, initializing it with the parameters provided.

import java.lang.reflect.Constructor;

public class Example {
    private String message;

    public Example(String message) {
        this.message = message;
    }

    public void showMessage() {
        System.out.println("Message: " + message);
    }

    public static void main(String[] args) {
        try {
            // Get the Class object associated with the Example class
            Class<Example> clazz = Example.class;
            
            // Get the Constructor object for the constructor that takes a String parameter
            Constructor<Example> constructor = clazz.getConstructor(String.class);
            
            // Use the Constructor object to create a new instance
            Example example = constructor.newInstance("Hello, Reflection!");
            
            // Call the showMessage method on the new instance
            example.showMessage(); // Output: Message: Hello, Reflection!
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Uses

  1. Dynamic Object Creation: Useful in frameworks and libraries where objects need to be created dynamically at runtime based on configuration or user input.
  2. Dependency Injection: Reflection can be used to create instances and inject dependencies dynamically in IoC (Inversion of Control) containers.
  3. Serialization/Deserialization: Custom serialization frameworks can use reflection to instantiate objects during the deserialization process.
  4. Testing: Creating instances of classes with private constructors for unit testing

Scroll to Top