CodeGym /Courses /JAVA 25 SELF /Creating objects via reflection

Creating objects via reflection

JAVA 25 SELF
Level 62, Lesson 3
Available

1. Creating objects via reflection

Sometimes we need to create objects without knowing their type at compile time. For example, the class name comes from configuration, or we are writing a generic framework (serializer, DI container). In regular code we would write:

User user = new User("John", 25);

But what if we don’t know that the class is called User and don’t know the constructor parameters? This is where reflection helps.

Deprecated approach: Class.newInstance()

Previously in Java there was a method Class.newInstance() that created an object via a public no‑arg constructor:

Class<?> clazz = Class.forName("com.example.User");
Object obj = clazz.newInstance();

IMPORTANT: This method has been marked as deprecated since Java 9 and is not recommended. It does not allow you to choose a constructor, hides the root causes of errors, and requires only a public no‑arg constructor.

Modern approach: via constructors

In real code there is often no public no‑arg constructor. The current approach is to obtain the required constructor via getConstructor(...) or getDeclaredConstructor(...), then call its newInstance(...).

Example: creating an object with parameters

public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
import java.lang.reflect.Constructor;

Class<?> clazz = Class.forName("User");
// Obtain the constructor with parameters String, int
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
// Create an object and pass the parameters
Object user = constructor.newInstance("John", 25);

System.out.println(user); // toString, if defined

What’s happening here?

  • We obtain the required constructor by signature.
  • We call newInstance(...) on it and pass arguments.
  • We get an object of type Object (you can cast it to User if the type is known).

What if the constructor is private?

Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true); // Magic! Now you can call a private constructor.
Object user = constructor.newInstance("John", 25);

WARNING: Don’t overuse this — it breaks encapsulation. In modular applications (Java 9+) access restrictions also apply.

Comparison table of object creation approaches

Approach Speed Type safety When to use
new User()
Fastest Full Always, when possible
Constructor.newInstance()
Slow Lost Frameworks, plugins
MethodHandle
Medium Partial High‑performance libraries
Factories Fast Full Flexible object creation

2. Invoking methods via reflection

You can invoke any method of an object even if you don’t know its name at compile time, or if it is private.

Obtaining a method

import java.lang.reflect.Method;

Class<?> clazz = user.getClass();
// Obtain a public method by name and parameter types
Method method = clazz.getMethod("getName"); // No parameters
Object result = method.invoke(user); // Invoke a method without parameters

System.out.println(result); // Will print the user’s name

Invoking a method with parameters

Method setName = clazz.getMethod("setName", String.class);
setName.invoke(user, "Peter"); // Set a new name

Invoking a private method

Method secret = clazz.getDeclaredMethod("secretMethod", int.class);
secret.setAccessible(true); // Remove access checks
Object secretResult = secret.invoke(user, 123);

Important: All parameters are passed as an array of objects (varargs). If the method returns something, the result will come back as an Object.

3. Accessing fields via reflection

Sometimes you need to read or change a field value even if it is private (for example, during serialization or testing).

Obtaining a field

import java.lang.reflect.Field;

Class<?> clazz = user.getClass();
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true); // If the field is not public

// Reading a value
Object age = ageField.get(user);
System.out.println("Age: " + age);

// Changing a value
ageField.set(user, 42);
System.out.println("New age: " + ageField.get(user));

Working with static fields

If the field is static, pass null instead of an instance to get/set:

Field staticField = clazz.getDeclaredField("counter");
staticField.setAccessible(true);
staticField.set(null, 100); // No instance needed for static fields

4. Limitations and exceptions

Working with reflection can involve many checked exceptions. The most common are:

  • ClassNotFoundException — no class with that name was found.
  • NoSuchMethodException — there is no constructor or method with that signature.
  • NoSuchFieldException — field not found.
  • IllegalAccessException — no access to the member (for example, a private method without setAccessible(true)).
  • InstantiationException — the class is abstract or an interface; cannot create an instance.
  • InvocationTargetException — an error inside the invoked constructor or method.

Handling example:

try {
    // ... your reflective code ...
} catch (ReflectiveOperationException e) {
    e.printStackTrace();
}

If details are not important, it’s more convenient to catch the common superclass ReflectiveOperationException (Java 7+).

5. Practice: mini program “Dynamic Instantiator”

Sample class for experiments

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private void sayHello() {
        System.out.println("Hello, my name is " + name + ", I am " + age + " years old.");
    }
}

Dynamic creation and manipulation

import java.lang.reflect.*;

public class ReflectionDemo {
    public static void main(String[] args) {
        try {
            // 1. Obtain a Class object by name
            Class<?> clazz = Class.forName("Person");

            // 2. Obtain the constructor and create an instance
            Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
            Object person = constructor.newInstance("Alice", 30);

            // 3. Invoke the private method sayHello
            Method sayHello = clazz.getDeclaredMethod("sayHello");
            sayHello.setAccessible(true);
            sayHello.invoke(person); // Hello, my name is Alice, I am 30 years old.

            // 4. Change the private field name
            Field nameField = clazz.getDeclaredField("name");
            nameField.setAccessible(true);
            nameField.set(person, "Bob");

            // 5. Invoke sayHello again
            sayHello.invoke(person); // Hello, my name is Bob, I am 30 years old.

        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }
}

Note:

  • Everything is done without direct knowledge of the Person type in the code.
  • You can change private fields and invoke private methods (provided this is allowed by the JVM security policy and module configuration).

6. How does this relate to real applications?

Reflection is at the core of many popular libraries and frameworks:

  • JUnit: find methods annotated with @Test, instantiate tests, and invoke methods.
  • Spring: DI, bean creation, autowiring.
  • Jackson, Gson: serialization/deserialization of object fields.
  • Hibernate: access to entity fields, proxies, and lazy loading.

7. Visual diagram: how an object is created via reflection

flowchart TB
    A["Class name (String)"] --> B["Class.forName"]
    B --> C["Class<?>"]
    C --> D["getConstructor(...)"]
    D --> E["Constructor<?>"]
    E --> F["newInstance(...)"]
    F --> G["Object"]

8. Common mistakes when working with reflection

Error #1: Wrong constructor. Requesting a constructor with the wrong signature, for example, getConstructor(String.class) when only a constructor with two parameters exists — you’ll get NoSuchMethodException. Always check signatures!

Error #2: Lack of access. Invoking a private constructor/method without setAccessible(true) leads to IllegalAccessException. And remember: in Java 9+ the module system may impose additional restrictions.

Error #3: Type issues. All parameters and return values via reflection are Object. Incorrect casting — ClassCastException.

Error #4: Uncaught exceptions. Reflection throws many checked exceptions. Handle them, for example by catching the common ReflectiveOperationException, otherwise the code will not compile.

Error #5: Encapsulation violation. Mindlessly using setAccessible(true) is “access to someone else’s fridge.” Use it only when truly necessary and consider security requirements.

1
Task
JAVA 25 SELF, level 62, lesson 3
Locked
Creating a Creature from Pure Energy 🧬
Creating a Creature from Pure Energy 🧬
1
Task
JAVA 25 SELF, level 62, lesson 3
Locked
Magical Creation of Ancient Tomes 📜
Magical Creation of Ancient Tomes 📜
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION