Example of creating an object using Class.newInstance()

Imagine you are assigned to create an object using reflection. Shall we get started?

We'll start by writing the code for the class we want to instantiate:


public class Employee {
    private String name;
    private String lastName;
    private int age;

    {
        age = -1;
        name = "Rob";
        surname = "Stark";
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return lastName;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", surname='" + surname + '\'' +
                ", age=" + age +
                '}';
    }
}

This will be our class — with several fields, a constructor with parameters, getters and setters, a toString() method, and an initialization block. Now let's move on to the second part: creating an object using reflection. The first approach we'll look at will use Class.newInstance().


public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Employee employee = Employee.class.newInstance();
        System.out.println("age is " + employee.getAge());
    }
}

Excellent! Let's run our code and watch for the age to be displayed. But we get an error about a missing default constructor. It turns out that this method only lets us get an object created using a default constructor. Let's add a default constructor for our class and test the code again.

Error message:

Code of the new constructor


public Employee() { }

After adding the constructor, here's the output:

age is 1

Great! We figured out how this method works. Now let's take a look under the hood. Cracking open the documentation, we see that our method is already deprecated:

It can also throw InstantiationException and IllegalAccessException. Accordingly, the documentation suggests that we use the other way of creating an object, namely Constructor.newInstance(). Let's analyze in detail how the Constructor class works.

getConstructors and getDeclaredConstructors methods

To work with the Constructor class, we first need to get an instance. We have two methods for this: getConstructors and getDeclaredConstructors.

The first returns an array of public constructors, and the second returns an array of all class constructors.

Let's give our class some privacy, or rather, let's create some private constructors to help demonstrate how these methods work.

Let's add some private constructors:


private Employee(String name, String surname) {
    this.name = name;
    this.lastName = lastName;
}

Looking at the code, note that one of the constructors is private:

Let's test our methods:


public class Main {
	  public static void main(String[] args) {
	      Class employeeClass = Employee.class;
	
	      System.out.println("getConstructors:");
	      printAllConstructors(employeeClass);
	
	      System.out.println("\n" +"getDeclaredConstructors:");
	      printDeclaredConstructors(employeeClass);
	  }
	
	  static void printDeclaredConstructors(Class<?> c){
	      for (Constructor<?> constructor : c.getDeclaredConstructors()) {
	          System.out.println(constructor);
	      }
	  }
	
	  static void printAllConstructors(Class<?> c){
	      for (Constructor<?> constructor : c.getConstructors()) {
	          System.out.println(constructor);
	      }
	  }
}

And we get this result:

getConstructors:
public en.codegym.Employee(java.lang.String,java.lang.String,int)
public.en.codegym.Employee()

getDeclaredConstructors:
private en.codegym.Employee(java.lang.String,java.lang.String)
public en.codegym.Employee(java.lang.String,java.lang.String,int)
public en.codegym.Employee()

Okay, this is how we get access to the Constructor object. Now we can talk about what it can do.

The java.lang.reflect.Constructor class and its most important methods

Let's take a look at the most important methods and how they work:

Method Description
getName() Returns the name of this constructor as a string.
getModifiers() Returns the Java access modifiers encoded as a number.
getExceptionTypes() Returns an array of Class objects that represent the types of exceptions declared by the constructor.
getParameters() Returns an array of Parameter objects representing all the parameters. Returns an array of length 0 if the constructor has no parameters.
getParameterTypes() Returns an array of Class objects that represent the formal parameter types in declaration order.
getGenericParameterTypes() Returns an array of Type objects that represent the formal parameter types in declaration order.

getName() & getModifiers()

Let's wrap our array in a List to make it convenient to work with. We'll also write getName and getModifiers methods:


static List<Constructor<?>> getAllConstructors(Class<?> c) {
    return new ArrayList<>(Arrays.asList(c.getDeclaredConstructors()));
}

static List<String> getConstructorNames(List<Constructor<?>> constructors) {
    List<String> result = new ArrayList<>();
    for (Constructor<?> constructor : constructors) {
        result.add(constructor.toString());
    }
    return result;
}

static List<String> getConstructorModifiers(List<Constructor<?>> constructors) {
    List<String> result = new ArrayList<>();
    for (Constructor<?> constructor : constructors) {
        result.add(Modifier.toString(constructor.getModifiers()));
    }
    return result;
}

And our main method, where we will call everything:


public static void main(String[] args) {
    Class employeeClass = Employee.class;
    var constructors = getAllConstructors(employeeClass);
    var constructorNames = getConstructorNames(constructors);
    var constructorModifiers = getConstructorModifiers(constructors);

    System.out.println("Employee class:");
    System.out.println("Constructors :");
    System.out.println(constructorNames);
    System.out.println("Modifiers :");
    System.out.println(constructorModifiers);
}

And now we see all the information we want:

Employee class:
Constructors :
[private en.codegym.Employee(java.lang.String), public
en.codegym.Employee(java.lang.String,java.lang.String,int), public en.codegym.Employee()]
Modifiers :
[private, public, public]

getExceptionTypes()

This method lets us get an array of the exceptions that our constructor may throw. Let's modify one of our constructors and write a new method.

Here we change our current constructor slightly:


private Employee(String name, String surname) throws Exception {
    this.name = name;
    this.lastName = lastName;
}

And here we have a method for getting exception types and add it to main:


static List<Class<?>> getConstructorExceptionTypes(Constructor<?> c) {
      return new ArrayList<>(Arrays.asList(c.getExceptionTypes()));
}


var constructorExceptionTypes = getConstructorExceptionTypes(constructors.get(0));
System.out.println("Exception types :");
System.out.println(constructorExceptionTypes);

Above, we accessed the first constructor in our list. We'll discuss how to get a specific constructor a little later.

And look at the output after we add throws Exception:

Exception types :
[class java.lang.Exception]

And before adding the exception:

Exception types :
[]

Everything is wonderful, but how do we see what parameters are required by our constructors? Let's figure out this as well.

getParameters() & getParameterTypes() & getGenericParameterTypes()

Let's start again by refining our private constructor. Now it will look like this:


private Employee(String name, String surname, List<String> list) {
    this.name = name;
    this.lastName = lastName;
}

And we have three additional methods: getParameters for getting the order of parameters and their types, getParameterTypes for getting the parameter types, and getGenericParameterTypes for getting types wrapped in generics.


static List<Parameter> getConstructorParameters(Constructor<?> c) {
    return new ArrayList<>(Arrays.asList(c.getParameters()));
}

static List<Class<?>> getConstructorParameterTypes(Constructor<?> c) {
    return new ArrayList<>(Arrays.asList(c.getParameterTypes()));
}

static List<Type> getConstructorParametersGenerics(Constructor<?> c) {
    return new ArrayList<>(Arrays.asList(c.getGenericParameterTypes()));
}

And we add some more information to our already not so small main method:


var constructorParameterTypes = getConstructorParameterTypes(constructors.get(0));
var constructorParameters = getConstructorParameters(constructors.get(0));
var constructorParametersGenerics = getConstructorParametersGenerics(constructors.get(0));

System.out.println("Constructor parameters :");
System.out.println(constructorParameters);

System.out.println("Parameter types :");
System.out.println(constructorParameterTypes);

System.out.println("Constructor parameter types :");
System.out.println(constructorParametersGenerics);

Looking at the output, we see very detailed information about the parameters of our constructors:

Constructor parameters :
[java.lang.String arg0, java.lang.String arg1, java.util.List<java.lang.String> arg2]
Parameter types :
[class java.lang.String, class java.lang.String, interface java.util.List]
Constructor parameter types :
[class java.lang.String, class java.lang.String, java.util.List<java.lang.String>]

This clearly demonstrates the difference between each method. We see that we have separate options to get information on parameter types, wrapped types, and everything in general. Super! Now that we're acquainted with the Constructor class, we can return to the main topic of our article — creating objects.

Creating an object using Constructor.newInstance()

The second way to create objects is to call the newInstance method on the constructor. Let's take a look at a working example and see how we can get a particular constructor.

If you want to get a single constructor, you should use the getConstructor method (not to be confused with getConstructors, which returns an array of all the constructors). The getConstructor method returns the default constructor.


public static void main(String[] args) throws NoSuchMethodException {
    Class employeeClass = Employee.class;
    Constructor<?> employeeConstructor = employeeClass.getConstructor();
    System.out.println(employeeConstructor);
}
public en.codegym.Employee()

And if we want to get a specific constructor, we need to pass the constructor's parameter types to this method.

Don't forget that we can only get our private constructor using the getDeclaredConstructor method.


Constructor<?> employeeConstructor2 = employeeClass.getDeclaredConstructor(String.class, String.class, List.class);
System.out.println(employeeConstructor2);

This is how we can get a specific constructor. Now let's try to create objects using private and public constructors.

Public constructor:


Class employeeClass = Employee.class;
Constructor<?> employeeConstructor = employeeClass.getConstructor(String.class, String.class, int.class);
System.out.println(employeeConstructor);

Employee newInstance = (Employee) employeeConstructor.newInstance("Rob", "Stark", 10);
System.out.println(newInstance);

The result is an object that we can work with:

public en.codegym.Employee(java.lang.String,java.lang.String,int)
Employee{name='Rob' surname='Stark', age=10}

Everything works great! Now we'll try with a private constructor:


Constructor<?> declaredConstructor = employeeClass.getDeclaredConstructor(String.class, String.class, List.class);
System.out.println(declaredConstructor);

Employee newInstance2 = (Employee) declaredConstructor.newInstance("Rob", "Stark", new ArrayList<>());
System.out.printf(newInstance2.toString());

The result is an error about the privacy of our constructor:

Java couldn't create an object using this constructor, but there is actually something magical we can do in the main method. We can our constructor's access level, making it possible to create objects of our class:


declaredConstructor.setAccessible(true);

Result of creating an object

private en.codegym.Employee(java.lang.String,java.lang.String,java.util.List)
Employee{name='Rob', surname='Stark', age=-1}

We don't set the age in our constructor, so it stays the same as when it was initialized.

Wonderful, let's sum up!

Benefits of creating objects using Constructor.newInstance()

Both methods share the same name, but there are differences between them:

Class.newInstance() Constructor.newInstance()
Can only call a no-arg constructor. Can call any constructor regardless of the number of parameters.
Requires the constructor to be visible. Can also call private constructors under certain circumstances.
Throws any exception (checked or not) that is declared by the constructor. Always wraps a thrown exception with InvocationTargetException.

For these reasons, Constructor.newInstance() is preferred over Class.newInstance(), and is the method used by various frameworks and APIs such as Spring, Guava, Zookeeper, Jackson, Servlet, etc.