Back to Blog
Java

Java Reflection Constructor: Inspect and Invoke at Runtime

java reflection constructor: Learn how to use Java reflection to inspect and invoke constructors, handle private and parameterized constructors, and instantiate object...

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 java reflection constructor APIs provide access to class 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 of the class and its superclasses. getDeclaredConstructors() returns all constructors declared in the class, regardless of access modifier, but does not include inherited 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 class is abstract or an interface.

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 a module system, the module must open the package to the caller, otherwise an InaccessibleObjectException is thrown. In a security manager environment, the operation may be denied. Use this feature only when you control the code and understand the consequences.

Performance and Maintainability Considerations

Reflection is significantly 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. Also consider using MethodHandle or VarHandle for better performance in Java 7 and later, but these come with their 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.

java reflection constructor: Practical Usage and Code Exampl | RYUSLOG DEV