Java Reflection for Constructors

1. Overview

A Constructor is used in the creation of an object that is an instance of a class. Typically it performs operations required to initialize the class before methods are invoked or fields are accessed. Constructors are never inherited.
The key classes used when working with constructors are Class and java.lang.reflect.Constructor.

The source code for this post is available on GitHub.

The below  class diagram show a list of Reflection APIs offered by java.lang.reflect.Constructor.
Java Reflection for Constructors

2. Reflection Constructors API Examples

  • Finding Constructors
  • Retrieving and Parsing Constructor Modifiers
  • Creating New Class Instances
  • Get Constructor
  • Get Constructor Information

2.1 Finding Constructors

A constructor declaration includes the name, modifiers, parameters, and list of throwable exceptions. The java.lang.reflect.Constructor class provides a way to obtain this information.
The ConstructorSift example illustrates how to search a class's declared constructors for one which has a parameter of a given type.
package com.javaguides.reflection.constructors;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import static java.lang.System.out;
 
public class ConstructorSift {
    public static void main(String... args) {
    try {
        Class<?> cArg = Class.forName("java.util.Locale");
 
        Class<?> c = Class.forName("java.util.Formatter");
        Constructor[] allConstructors = c.getDeclaredConstructors();
        for (Constructor ctor : allConstructors) {
        Class<?>[] pType  = ctor.getParameterTypes();
        for (int i = 0; i < pType.length; i++) {
            if (pType[i].equals(cArg)) {
            out.format("%s%n", ctor.toGenericString());
 
            Type[] gpType = ctor.getGenericParameterTypes();
            for (int j = 0; j < gpType.length; j++) {
                char ch = (pType[j].equals(cArg) ? '*' : ' ');
                out.format("%7c%s[%d]: %s%n", ch,
                       "GenericParameterType", j, gpType[j]);
            }
            break;
            }
        }
        }
 
        // production code should handle this exception more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}
Output:
public java.util.Formatter(java.lang.String,java.lang.String,java.util.Locale) 
throws java.io.FileNotFoundException,java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.lang.String
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
public java.util.Formatter(java.io.File,java.lang.String,java.util.Locale) 
throws java.io.FileNotFoundException,java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.io.File
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
private java.util.Formatter(java.nio.charset.Charset,java.util.Locale,java.io.File) 
throws java.io.FileNotFoundException
       GenericParameterType[0]: class java.nio.charset.Charset
      *GenericParameterType[1]: class java.util.Locale
       GenericParameterType[2]: class java.io.File
private java.util.Formatter(java.util.Locale,java.lang.Appendable)
      *GenericParameterType[0]: class java.util.Locale
       GenericParameterType[1]: interface java.lang.Appendable
public java.util.Formatter(java.io.OutputStream,java.lang.String,java.util.Locale) 
throws java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.io.OutputStream
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
public java.util.Formatter(java.lang.Appendable,java.util.Locale)
       GenericParameterType[0]: interface java.lang.Appendable
      *GenericParameterType[1]: class java.util.Locale
public java.util.Formatter(java.util.Locale)
      *GenericParameterType[0]: class java.util.Locale

2.2 Retrieving and Parsing Constructor Modifiers

Because of the role of constructors in the language, fewer modifiers are meaningful than for methods:
  • Access modifiers: public, protected, and private
  • Annotations
The ConstructorAccess example searches for constructors in a given class with the specified access modifier. It also displays whether the constructor is synthetic (compiler-generated) or of variable arity.
package com.javaguides.reflection.constructors;

import static java.lang.System.out;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class ConstructorAccess {
 public static void main(String... args) {
  try {
      Class<?> c = Class.forName("java.io.File");
      Constructor[] allConstructors = c.getDeclaredConstructors();
      for (Constructor ctor : allConstructors) {
          int searchMod = modifierFromString("private");
          int mods = accessModifiers(ctor.getModifiers());
          if (searchMod == mods) {
             out.format("%s%n", ctor.toGenericString());
             out.format("  [ synthetic=%-5b var_args=%-5b ]%n", ctor.isSynthetic(), ctor.isVarArgs());
          }
      }

     // production code should handle this exception more gracefully
  } catch (ClassNotFoundException x) {
      x.printStackTrace();
  }
 }

 private static int accessModifiers(int m) {
     return m & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED);
 }

 private static int modifierFromString(String s) {
     if ("public".equals(s))
         return Modifier.PUBLIC;
     else if ("protected".equals(s))
         return Modifier.PROTECTED;
     else if ("private".equals(s))
         return Modifier.PRIVATE;
     else if ("package-private".equals(s))
         return 0;
     else
         return -1;
 }
}
Output:
private java.io.File(java.lang.String,java.io.File)
  [ synthetic=false var_args=false ]
private java.io.File(java.lang.String,int)
  [ synthetic=false var_args=false ]

2.3 Creating New Class Instances

There are two reflective methods for creating instances of classes: java.lang.reflect.Constructor.newInstance() and Class.newInstance().
package com.javaguides.reflection.constructors;

import java.io.Console;
import java.nio.charset.Charset;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;

public class ConsoleCharset {
 public static void main(String... args) {
     Constructor[] ctors = Console.class.getDeclaredConstructors();
     Constructor ctor = null;
     for (int i = 0; i < ctors.length; i++) {
        ctor = ctors[i];
         if (ctor.getGenericParameterTypes().length == 0)
          break;
     }

     try {
        ctor.setAccessible(true);
        Console c = (Console) ctor.newInstance();
        Field f = c.getClass().getDeclaredField("cs");
        f.setAccessible(true);
        out.format("Console charset         :  %s%n", f.get(c));
        out.format("Charset.defaultCharset():  %s%n", Charset.defaultCharset());

        // production code should handle these exceptions more gracefully
        } catch (InstantiationException x) {
            x.printStackTrace();
        } catch (InvocationTargetException x) {
            x.printStackTrace();
        } catch (IllegalAccessException x) {
            x.printStackTrace();
        } catch (NoSuchFieldException x) {
            x.printStackTrace();
        }
    }
}
Output:
Console charset         :  windows-1252
Charset.defaultCharset():  windows-1252
Let's learn few more examples, first create Customer.java class and apply Reflection Constructor API on Customer class.

Customer.java

package com.javaguides.reflection.constructors;

public class Customer {
    private int id;
    private String firstName;
    private String lastName;
    public Customer(int id, String firstName, String lastName) {
        super();
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getFirstName() {
       return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getLastName() {
       return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

2.4 Get Constructor

_ getConstructor()_ method on the class representation of an object to get specific public constructor.
Class<?> clazz = Class.forName("com.javaguides.reflection.constructors.Customer");

Constructor<?> constructor = clazz.getConstructor(int.class, String.class, String.class);

// getting constructor parameters
System.out.println(Arrays.toString(constructor.getParameterTypes()));

Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);

System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes()));
Output:
[int, class java.lang.String, class java.lang.String]
[]

2.5 Get Constructor Information

Let's use Constructor Reflection API's to obtain Customer Constructor information.
   Class<?> clazz = Class.forName("com.javaguides.reflection.constructors.Customer");
   Constructor[] constructors = clazz.getConstructors();
   for (Constructor<?> constructor : constructors) {

      // get constructor name
      System.out.println(constructor.getName());

      // get constructor parameters
      System.out.println(Arrays.toString(constructor.getParameterTypes()));

      // Get parameter count
      System.out.println(constructor.getParameterCount());

     System.out.println(constructor.getDeclaringClass().getCanonicalName());
   }
Output:
com.javaguides.reflection.constructors.Customer
[int, class java.lang.String, class java.lang.String]
3
com.javaguides.reflection.constructors.Customer

3. Reference

Comments