Wednesday, 26 July 2017

Reflection in Java - Constructor

Similar to reflection API for methods, there is also reflection API to get information about the constructors of a class. Using java.lang.reflect.Constructor you can get information about the modifiers, parameters, annotations, and thrown exceptions. You can also create a new instance of a class using a specified constructor.

How to get Constructor object

As always the starting point is the Class and there are four methods provided by the class Class for getting the constructors.
  • getConstructor(Class<?>... parameterTypes) - Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. The parameterTypes parameter is an array of Class objects that identify the constructor's formal parameter types, in declared order.
  • getConstructors() - Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object.
  • getDeclaredConstructor(Class<?>... parameterTypes) – Returns a Constructor object that reflects the specified constructor of the class or interface represented by this Class object. The parameterTypes parameter is an array of Class objects that identify the constructor's formal parameter types, in declared order.
  • getDeclaredConstructors() - Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object. These are public, protected, default (package) access, and private constructors.

Example code

For example we’ll be using this class TestClass which has one public constructor with 2 args and a private constructor.

TestClass.java

public class TestClass {
 private int value;
 private String name;
 // public Constructor
 public TestClass(int value, String name) {
  
  this.value = value;
 }
 // private constructor
 private TestClass() {
  
 }
 
 public void showValue() {
  System.out.println("Value - " + value);
  
 }
 
}

If you want to get constructors using the above 4 methods it can be done as follows –

import java.lang.reflect.Constructor;
import java.util.Arrays;

public class ReflectConstructor {

 public static void main(String[] args) {
  try {
   Class<?> c = Class.forName("org.prgm.TestClass");
   // To get constructor with 2 args
   Constructor<?> constructor = c.getConstructor(int.class, String.class);
   //Constructor<?> constructor = c.getConstructor(new Class[]{int.class, String.class});
   
   System.out.println("constructor " + constructor.toString());
   // to get private constructor using getDeclaredConstructor() method
   constructor = c.getDeclaredConstructor();
   System.out.println("constructor " + constructor.toString());
   
   // Getting constructors of the class
   Constructor<?>[] constructors = c.getConstructors();
   System.out.println("Constructors - " + Arrays.toString(constructors));
   
   Constructor<?>[] Decconstructors = c.getDeclaredConstructors();
   System.out.println("Declared constructors - " + Arrays.toString(Decconstructors));
  } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }

}

Output

constructor public org.prgm.TestClass(int,java.lang.String)
constructor private org.prgm.TestClass()
Constructors - [public org.prgm.TestClass(int,java.lang.String)]
Declared constructors - [public org.prgm.TestClass(int,java.lang.String), private org.prgm.TestClass()]

Here note that in the first call two parameters are passed with the getConstructor() method which match the arguments of the constructor in the TestClass class. Since parameter is defined as varargs in getConstructor() so you can pass as comma separated parameters or as an array of class objects. Which is done as an illustration in the commented code.

Second call uses the getDeclaredConstructor(); method as that can return constructor object pertaining to private constructor too.

Same way getDeclaredConstructors() method returns an array of Constructor objects reflecting all the constructors of the class public or private where as getConstructors() method returns an array of constructor objects reflecting all the public constructors of the class.

Example code

Class<?> c = Class.forName("org.prgm.TestClass");
Constructor<?>[] Decconstructors = c.getDeclaredConstructors();
for(Constructor<?> ctr : Decconstructors){
 System.out.println("Constructor -- " + ctr.getName());
 Class<?>[] pType  = ctr.getParameterTypes();
 for (int i = 0; i < pType.length; i++) {
  System.out.println("Parameter -- " + pType[i]);
 }
}

Getting modifiers of the constructors

You can get modifiers of the constructors of the class through reflection using getModifiers() method.

Example code

Class<?> c = Class.forName("org.prgm.TestClass");
Constructor<?>[] Decconstructors = c.getDeclaredConstructors();
for(Constructor<?> ctr : Decconstructors){
 System.out.println("Constructor -- " + ctr.getName() + " has modifier " 
  +  Modifier.toString(ctr.getModifiers()));
}

Output

Constructor -- org.prgm.TestClass has modifier public
Constructor -- org.prgm.TestClass has modifier private

Creating class instance

In reflection API there are two methods for creating instances of classes - java.lang.reflect.Constructor.newInstance() and Class.newInstance(). It is preferable to go with the one provided by the Constructor class for the reasons explained here -

  1. Class.newInstance() can only invoke the zero-argument constructor, while Constructor.newInstance() may invoke any constructor, regardless of the number of parameters.
  2. Class.newInstance() requires that the constructor be visible; Constructor.newInstance() can invoke private constructors also by setting accessibility to true.
  3. Class.newInstance() throws any exception thrown by the constructor whether it is checked or unchecked exception. Constructor.newInstance() always wraps the thrown exception with an InvocationTargetException.

Example code

For the TestClass.java which has one public constructor with two arguments and one no-arg private constructor, creating new class instances can be done as follows.

Class<?> c = Class.forName("org.prgm.TestClass");
Constructor<?>[] Decconstructors = c.getDeclaredConstructors();
for(Constructor<?> ctr : Decconstructors){
 System.out.println("Constructor -- " + ctr.getName());
 try {
  TestClass t;
  if(Modifier.toString(ctr.getModifiers()).equals("private")){
   // Setting accessibility to true if it's a private constructor
   ctr.setAccessible(true);
   t = (TestClass)ctr.newInstance();
  }else{
   t = (TestClass)ctr.newInstance(100, "InstanceTest");
  }   
  t.showValue();
    
 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
   e.printStackTrace();
 }   
}

Output

Constructor -- org.prgm.TestClass
Value - 100
Constructor -- org.prgm.TestClass
Value – 0

In the code there is a check for the modifier of the constructor. If it is private then the set the accessible flag to true, with that even private constructor can be accessed from another class and an instance created.

That's all for this topic Reflection in Java - Constructor. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Reflection in Java - Class
  2. Reflection in Java - Field
  3. Serialization in Java

You may also like -

>>>Go to Java advance topics page

No comments:

Post a Comment