skip to content

How do you call a method on an object dynamically at runtime using reflection, and what does Method.invoke return?

level: juniorimportance: must knowfreq 60%

answer

  1. getMethod (public+inherited) vs getDeclaredMethod (any access, this class only)
  2. invoke(target, args); target null for static
  3. return is Object; void -> null; primitives boxed
  4. InvocationTargetException wraps the method's own throw — getCause()
  5. setAccessible(true) for non-public

basics

~20 s

Get a Method object from the class (e.g. clazz.getMethod("name", paramTypes)), then call method.invoke(target, args). The first argument is the object to call it on (null for static methods); it returns the method's result as an Object.

solid answer

~40 s

Reflection lets you call a method whose name you only know at runtime. You obtain a java.lang.reflect.Method via getMethod (public, including inherited) or getDeclaredMethod (any access level, declared on that class only), passing the method name and the parameter types as Class objects. Then you call method.invoke(target, args...): target is the receiving instance (null for a static method) and args are autoboxed Objects. The return value is always Object — you cast it, and a void method returns null. Primitive returns are boxed (int becomes Integer). Checked exceptions from the target are wrapped in InvocationTargetException; use getCause() to reach the real one. If the method is non-public you must call setAccessible(true) first (subject to module rules).

code

java · 6 lines
java
Method m = obj.getClass().getMethod("greet", String.class);
try {
    String out = (String) m.invoke(obj, "world"); // obj.greet("world")
} catch (InvocationTargetException e) {
    Throwable real = e.getCause(); // exception thrown inside greet()
}

go deeper

for a junior

Knows the basic recipe: getMethod, then invoke(target, args), result is Object, null target for static.

for a middle

Distinguishes getMethod vs getDeclaredMethod, knows primitives box/unbox, and unwraps InvocationTargetException via getCause().

for a senior

Explains the access-control interaction (setAccessible, module openness) and why exception wrapping exists; handles the full exception set cleanly.

for a principal

Discusses when reflective invocation is appropriate vs MethodHandles/codegen, caching Method objects, and module-system constraints in library design.

## What problem this solves Normally in Java you call a method by writing its name directly: `obj.doThing()`. The compiler checks it exists and links the call. **Reflection** is the Java API (in `java.lang.reflect`) that lets your program inspect and use classes, methods, and fields whose names it may not know until the program is already running. "Dynamic invocation" means: *call a method chosen at runtime*, for example a method whose name came from a config file or a plugin. ## Step 1 — get a `Class` object Everything starts from a `java.lang.Class` instance, which represents a loaded type. You get one via `obj.getClass()`, `MyType.class`, or `Class.forName("com.acme.MyType")`. ## Step 2 — get a `Method` object A `java.lang.reflect.Method` represents one method. Two lookups: - `clazz.getMethod(String name, Class<?>... parameterTypes)` — returns a **public** method, **including inherited** ones (searches superclasses/interfaces). - `clazz.getDeclaredMethod(String name, Class<?>... parameterTypes)` — returns a method of **any** access level (private, protected, package), but **only one declared directly on that class** (not inherited). You must pass the exact **parameter types** as `Class` objects so Java can find the right overload. For a method `greet(String, int)` you pass `String.class, int.class`. Primitives use their `.class` literal (`int.class`, not `Integer.class`). ## Step 3 — invoke ```java Object result = method.invoke(target, arg1, arg2); ``` - `target` is the **instance** the call runs on. For a **static** method pass `null`. - The remaining arguments are the call arguments, **autoboxed** into `Object` (an `int` argument is passed as an `Integer`). - The **return type is always `Object`**. You cast it to the type you expect. A `void` method returns `null`. A primitive return is **boxed** (an `int` result comes back as an `Integer`). ## Exceptions you must handle - `NoSuchMethodException` — thrown by the lookup if no matching method exists. - `IllegalAccessException` — the method isn't accessible from your code (e.g. it's private and you didn't enable access). - `IllegalArgumentException` — wrong target type or wrong argument types/count. - `InvocationTargetException` — **the most important one**: if the target method itself throws an exception, reflection catches it and rethrows it wrapped. Call `getCause()` to get the original exception. This wrapping exists so reflection can distinguish *"the call mechanism failed"* from *"your method threw."* ## Access control If you looked up a non-public member, you must call `method.setAccessible(true)` before invoking, which suppresses Java's access checks. Under the Java Platform Module System (Java 9+) this only works if the target package is **open** to your module; otherwise you get an `InaccessibleObjectException`. ## Full example ```java Method m = obj.getClass().getMethod("greet", String.class); String out = (String) m.invoke(obj, "world"); // calls obj.greet("world") ``` From this you can derive: how to call any named method, how primitives are boxed both ways, and why you unwrap `InvocationTargetException`.

  • Your invoked method throws an IllegalStateException. What exception does the caller of invoke() actually catch?
    InvocationTargetException. The real IllegalStateException is its getCause(). Reflection wraps any exception thrown by the target method so you can distinguish it from invocation-mechanism failures.
  • What's the difference between getMethod and getDeclaredMethod?
    getMethod returns only public methods but searches the whole hierarchy (inherited too). getDeclaredMethod returns methods of any access level but only those declared directly on that class, not inherited ones.

saying these in an interview costs you the question

  • Thinking the target method's checked exception propagates directly — it's wrapped in InvocationTargetException.
  • Passing Integer.class instead of int.class for a primitive parameter (overload won't be found).
  • Assuming getMethod finds private methods — it only finds public ones.
  • Forgetting that invoke returns Object and a void method returns null, not the receiver.

context