Back to Blog
Java

Java Reflection Constructor: Inspect and Invoke at Runtime

Use Java reflection to inspect and invoke constructors at runtime, including public, private, and parameterized constructors, with code examples.

JavaReflectionConstructorsDynamic InstantiationRuntime Introspection
Diagram showing Java reflection constructor inspection and invocation process

When you need to create an object without knowing its class at compile time, Java reflection lets you inspect and invoke constructors dynamically. The reflection API exposes constructor metadata, allowing you to find the right constructor, handle accessibility, and instantiate objects at runtime.

Getting Constructor Objects with getConstructors() and getDeclaredConstructors()

The Class object provides two methods for retrieving constructors. getConstructors() returns only public constructors declared by the class. getDeclaredConstructors() returns all constructors declared in the class, regardless of access modifier. Constructors are not inherited, so neither method returns superclass constructors. For most dynamic instantiation scenarios, getDeclaredConstructors() is the more useful method because it exposes private, protected, and package-private constructors that you might need to invoke.

Class<?> clazz = MyClass.class; Constructor<?>[] publicConstructors = clazz.getConstructors(); Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();

Each Constructor object represents a single constructor signature. You can inspect its parameter types, modifiers, and annotations before deciding which one to invoke.

Choosing the Right Constructor with getConstructor() and getDeclaredConstructor()

When you know the exact parameter types, you can retrieve a specific constructor directly. getConstructor(Class<?>... parameterTypes) works only for public constructors. getDeclaredConstructor(Class<?>... parameterTypes) works for any constructor declared in the class, including private ones. Both throw NoSuchMethodException if the signature does not exist.

Constructor<MyClass> constructor = MyClass.class.getDeclaredConstructor(String.class, int.class);

The order of parameter types must match the declaration exactly. Primitive types and their wrapper classes are considered distinct, so int.class is not the same as Integer.class. This is a common source of NoSuchMethodException when the constructor uses primitives but you pass wrapper classes.

Invoking a Constructor with newInstance()

Once you have a Constructor object, you can create a new instance by calling newInstance(Object... initargs). The arguments passed must match the parameter types in both number and type. The return type is Object, so you usually cast it to the expected type.

MyClass instance = (MyClass) constructor.newInstance("value", 42);

newInstance() wraps any exception thrown by the constructor itself in an InvocationTargetException. This means you need to unwrap the cause to see the original error. The method also throws IllegalAccessException if the constructor is not accessible and you have not called setAccessible(true), and InstantiationException if the declaring class is abstract.

Handling Private and Non-Public Constructors with setAccessible()

Reflection respects Java access control by default. To invoke a private constructor, you must call setAccessible(true) on the Constructor object. This suppresses the access check for that specific instance. It works for package-private and protected constructors as well.

constructor.setAccessible(true); MyClass instance = constructor.newInstance("hidden", 7);

Calling setAccessible(true) has security implications. In the Java module system, the module containing the target class must open its package to the module containing the calling code, otherwise an InaccessibleObjectException is thrown. If a Security Manager is installed, the operation may be denied. Use this feature only when you control the code and understand the consequences.

Performance and Maintainability Considerations

Reflection is slower than direct constructor invocation because the JVM performs type checks, argument boxing, and access checks at runtime. In performance-critical paths, avoid calling newInstance() repeatedly. If you must use reflection, cache the Constructor object and reuse it. The MethodHandle API, introduced in Java 7, is a lower-level alternative for dynamic invocation, but it comes with its own complexity.

From a maintainability perspective, reflection makes code harder to read and debug. It bypasses compile-time type safety and can hide errors until runtime. Use it only when you genuinely need dynamic behavior, such as in dependency injection containers, serialization libraries, or plugin systems. For ordinary object creation, prefer direct instantiation.

Common Errors and How to Avoid Them

A frequent error is NoSuchMethodException when the parameter types do not match exactly. Check the actual signature using getDeclaredConstructors() and inspect the parameter types. Another error is IllegalAccessException when you forget to call setAccessible(true) on a non-public constructor. Finally, remember that InvocationTargetException wraps the real exception; call getCause() to see the underlying failure.

try { constructor.setAccessible(true); return constructor.newInstance(args); } catch (InvocationTargetException e) { throw e.getCause(); }

This pattern preserves the original exception and avoids masking the actual problem. If the enclosing method cannot declare throws Throwable, wrap the cause in an exception type your API permits instead.

Java Reflection Constructor: Inspect and Invoke Constructors at Runtime | RYUSLOG DEV