Working with Reflection API
1. Getting Class Objects
| Source | Syntax |
| Literal | String.class |
| Instance | obj.getClass() |
| Name | Class.forName("com.X") |
| Loader | cl.loadClass("com.X") |
| Primitive | int.class, void.class |
2. Inspecting Class Members
| Method | Visibility |
getFields() | Public, including inherited |
getDeclaredFields() | All declared in this class |
getMethods() | Public, inherited |
getDeclaredMethods() | All declared |
getConstructors / getDeclaredConstructors | Same pattern |
getRecordComponents() | Records (Java 16+) |
3. Accessing Private Members (setAccessible)
| Aspect | Detail |
setAccessible(true) | Bypasses Java access checks |
| Modules (JPMS) | Requires opens directive |
| Java 17+ | Strong encapsulation by default |
| Override | --add-opens java.base/java.lang=ALL-UNNAMED |
Warning: Reflection on JDK internals throws InaccessibleObjectException on Java 17+. Use public APIs or VarHandle.
4. Invoking Methods Dynamically (Method.invoke)
| Step | Code |
| Lookup | cls.getMethod("name", paramTypes) |
| Invoke | m.invoke(target, args) |
| Static | Pass null as target |
| Exceptions | Wraps in InvocationTargetException |
5. Creating Instances (Constructor.newInstance)
| API | Use |
cls.getDeclaredConstructor(paramTypes).newInstance(args) | Modern preferred |
cls.newInstance() DEPRECATED | Java 9+ |
| No-arg | Must exist; setAccessible for private |
6. Modifying Field Values
| Method | Use |
field.get(obj) | Read |
field.set(obj, value) | Write |
| Static | field.get(null) |
| Primitive specializations | getInt, setLong, etc. |
| Final fields | Java 17+ rejects (use VarHandle) |
7. Working with Annotations
| API | Element |
getAnnotation(A.class) | Class/Method/Field |
getDeclaredAnnotations() | All declared |
getParameterAnnotations() | 2D array per param |
8. Inspecting Generic Types (getGenericType)
| API | Returns |
field.getGenericType() | Type (could be ParameterizedType) |
method.getGenericReturnType() | Type |
cls.getGenericSuperclass() | Type with type args |
| Cast to | ParameterizedType.getActualTypeArguments() |
| Cost | Mitigation |
| Lookup | Cache Method/Field instances |
| Access checks | setAccessible(true) once |
| Boxing/unboxing | Use specialized methods |
| vs direct call | ~5–20× slower; JIT can inline cached refs |
| Better | MethodHandle / LambdaMetafactory |
10. Using MethodHandles as Alternative
| vs Reflection | MethodHandle |
| Speed | Near-native after JIT |
| Type safety | MethodType at lookup |
| Access | Captured at lookup; checks once |
| Use | High-frequency dynamic calls |
Example: Lookup + invoke
MethodHandles.Lookup lk = MethodHandles.lookup();
MethodHandle mh = lk.findVirtual(String.class, "length", MethodType.methodType(int.class));
int n = (int) mh.invokeExact("hello"); // 5