W3docs

Java Reflection: Calling Constructors

Instantiate Java classes reflectively with Constructor.newInstance and Class.getDeclaredConstructor.

Java Reflection: Calling Constructors

Creating an object without writing new is the reflective trick behind every dependency-injection container, deserializer, and plugin loader: you have a Class, and you need an instance. The Constructor<T> object represents one constructor and builds instances with newInstance(args...). This chapter covers finding constructors, calling them with arguments, reaching private constructors, and why the old Class.newInstance() shortcut is deprecated.

Finding constructors

Constructors are looked up by parameter types only — there's no name, since all constructors share the class's name:

Class<User> c = User.class;

Constructor<User> noArg  = c.getDeclaredConstructor();                  // ()
Constructor<User> twoArg = c.getDeclaredConstructor(String.class, int.class);  // (String, int)

Constructor<?>[] pub  = c.getConstructors();          // public only
Constructor<?>[] all  = c.getDeclaredConstructors();  // any access level

As everywhere in reflection, parameter types must match exactly (int.class, not Integer.class), and getConstructor sees only public ones while getDeclaredConstructor sees private/protected/package too. Note Constructor<T> is generic in the class it builds, so newInstance returns a typed T (unlike Method.invoke's raw Object).

Building instances with newInstance

Constructor<User> ctor = User.class.getDeclaredConstructor(String.class, int.class);
User u = ctor.newInstance("ada", 36);     // returns a typed User

Arguments work just like Method.invoke: a varargs Object[], primitives autoboxed. The difference is there's no target object — a constructor creates the target. Exceptions thrown by the constructor body are wrapped in InvocationTargetException, exactly as with methods; unwrap with getCause().

Reaching private constructors

Singletons, utility classes, and builders often hide their constructor. Reflection walks right past that with setAccessible(true):

Constructor<Singleton> ctor = Singleton.class.getDeclaredConstructor();
ctor.setAccessible(true);                 // bypass the private modifier
Singleton fresh = ctor.newInstance();     // a SECOND instance — breaks the singleton!

This is genuinely powerful and genuinely dangerous: it defeats the singleton guarantee, the "no instances" contract of a utility class, and any invariant the constructor was protecting. (An enum singleton is the one form reflection cannot instantiate — Constructor.newInstance explicitly refuses enum types with IllegalArgumentException, which is part of why "enum singleton" is the recommended pattern.)

Why Class.newInstance() is deprecated

You'll see old code use the shortcut clazz.newInstance():

User u = User.class.newInstance();   // DEPRECATED since Java 9

It's deprecated for two real reasons:

  1. It only calls the no-arg constructor. No way to pass arguments.
  2. It mishandles exceptions. If the no-arg constructor throws a checked exception, Class.newInstance() propagates it without declaring it — defeating the compiler's checked-exception analysis.

The replacement is always:

User u = User.class.getDeclaredConstructor().newInstance();

This is one line longer, calls a constructor you chose explicitly, and wraps constructor exceptions in InvocationTargetException so nothing escapes undeclared. Use it as the standard idiom even for the no-arg case.

A worked example: a tiny reflective factory

The program builds objects three ways: a public multi-arg constructor, a private constructor reached via setAccessible, and the modern no-arg idiom — then shows a constructor that throws being wrapped, and the deprecated shortcut's signature for contrast.

java— editable, runs on the server

What to take from the run:

  • The generic build factory created Widget and Hidden from a Class plus a parameter-type array — naming neither type in a new expression. That signature, <T> T build(Class<T>, Class<?>[], Object...), is essentially what a DI container's instantiation core looks like: hand it a type and arguments, get back an instance.
  • getDeclaredConstructor().newInstance() produced the default Widget, demonstrating the modern replacement for Class.newInstance(). Always prefer it: it lets you choose the constructor and it routes constructor exceptions through InvocationTargetException instead of leaking undeclared checked exceptions.
  • The reflective Hidden instance was not the same object as Hidden.INSTANCE (same instance? false). setAccessible(true) walked straight past the private constructor and minted a second instance — concrete proof that reflection can break a singleton's core guarantee. Defensive singletons throw from the constructor if an instance already exists; enums are immune by construction.
  • The constructor that rejected a negative size threw IllegalArgumentException from its body, and that surfaced as InvocationTargetException with the real cause inside — identical wrapping to Method.invoke. Construction-time validation is preserved through reflection; you just have to unwrap to see it.
  • Constructor<T> returned a typed T (Widget, Hidden) with no cast, unlike Method.invoke's raw Object. Because the constructor is generic in the class it builds, the factory stays type-safe at its boundary even though everything inside is reflective.

Practice

Practice

A teammate writes 'MyService s = MyService.class.newInstance();' and the linter flags 'newInstance()' as deprecated. What is the recommended replacement, and what is the main practical reason the old form was deprecated?