Java getMethods: Discovering Public Methods with Reflection
java getmethods: Learn how to use Java's getMethods() to discover public methods at runtime, including its behavior, differences from getDeclaredMethods(), and practic...
When you need to inspect the public methods of a class at runtime, java getmethods — specifically the getMethods() method from java.lang.Class — is the standard entry point. It returns an array of Method objects representing all public methods of the class, including those inherited from superclasses and interfaces. This is a core part of Java's reflection API, used in frameworks, serialization libraries, and testing tools to discover what a class can do without knowing its structure at compile time.
What getMethods() Actually Returns
getMethods() returns a Method[] containing public methods that are accessible from the class itself. This includes:
- Public methods declared in the class.
- Public methods inherited from superclasses.
- Public methods inherited from interfaces (default methods).
It does not include package-private, protected, or private methods. For example, consider a simple class hierarchy:
public class Animal { public void eat() { } protected void sleep() { } } public class Dog extends Animal { public void bark() { } private void wagTail() { } }
Calling Dog.class.getMethods() returns bark() and eat() — the public methods from Dog and its superclass Animal. The protected sleep() and private wagTail() are excluded. The order of methods in the array is not guaranteed; it depends on the JVM and the class representation.
getMethods() vs getDeclaredMethods(): Choosing the Right Tool
Developers often confuse getMethods() with getDeclaredMethods(). The distinction is critical for correct reflection logic. getDeclaredMethods() returns all methods declared directly in the class, regardless of access modifier, but does not include inherited methods.
| Method | Scope | Access Modifiers | Inherited Methods |
|---|---|---|---|
getMethods() | Public methods only | Public | Yes |
getDeclaredMethods() | All declared methods | Public, protected, package, private | No |
Use getMethods() when you need to interact with the public API of an object, such as invoking a method that is guaranteed to be callable from outside the class. Use getDeclaredMethods() when you need to inspect or invoke private or package-private methods, for example in unit testing or when implementing a framework that must access internal state.
Using getMethods() in Practice
A typical use case is to list all public method names of a class. Here is a minimal example:
import java.lang.reflect.Method; public class MethodLister { public static void main(String[] args) { Class<?> clazz = String.class; Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method.getName()); } } }
This prints all public methods of String, including those inherited from Object like equals, hashCode, and toString. If you only want methods declared in the class itself, you would need to filter out inherited ones, but getMethods() does not provide that distinction directly. You can check the declaring class using method.getDeclaringClass() to see where each method originates.
Inspecting and Invoking Methods from getMethods()
Each Method object returned by getMethods() provides rich metadata: parameter types, return type, annotations, and the ability to invoke the method dynamically. For instance, to invoke a public method by name:
import java.lang.reflect.Method; public class Invoker { public static void main(String[] args) throws Exception { Class<?> clazz = String.class; Method method = clazz.getMethod("toUpperCase"); String result = (String) method.invoke("hello"); System.out.println(result); // HELLO } }
Note that getMethod() (singular) is a convenience method that searches for a specific public method by name and parameter types. It relies on the same underlying mechanism as getMethods() but throws NoSuchMethodException if no match is found. When using getMethods(), you typically iterate over the array and check conditions manually, which gives you more flexibility for filtering based on annotations or parameter signatures.
Performance and Runtime Cost of Reflection
Reflection is inherently slower than direct method calls because the JVM must resolve method references dynamically, perform access checks, and box arguments. getMethods() itself is relatively cheap when called once, but repeated calls on the same class can add overhead. The JVM may cache reflection data, but it is still advisable to cache the Method[] array if you need to inspect the same class multiple times.
A more significant cost comes from invoking methods via reflection. Each Method.invoke() call incurs overhead compared to a direct call. In performance-sensitive code, such as a tight loop that processes thousands of objects, reflection can become a bottleneck. If you must use reflection, consider caching the Method objects and using java.lang.invoke.MethodHandle for better performance in modern JVMs.
Common Pitfalls and Edge Cases
One common mistake is assuming getMethods() returns methods in declaration order. It does not; the order is unspecified. If your logic depends on a specific order, sort the array explicitly.
Another pitfall is ignoring exceptions. getMethods() can throw SecurityException if a security manager is present and denies access to the class metadata. In standard environments this is rare, but in sandboxed environments like applets or custom class loaders, you must handle it.
Also, be aware that getMethods() includes bridge methods and synthetic methods generated by the compiler. For example, when a generic class implements a generic interface, the compiler may generate bridge methods. These appear in the array and can confuse logic that expects only user-defined methods. You can filter them using method.isBridge() or method.isSynthetic().
Finally, when dealing with interfaces, getMethods() returns default methods and static methods (since Java 8). Static interface methods are included, but they cannot be invoked on an instance; they require the interface class itself. Keep this in mind when writing generic invocation logic.
Using getMethods() with Annotations and Filtering
A powerful pattern is to combine getMethods() with annotation scanning. For example, a framework might look for public methods annotated with @PostConstruct:
import java.lang.reflect.Method; public class AnnotationScanner { public static void main(String[] args) { Class<?> clazz = MyService.class; for (Method method : clazz.getMethods()) { if (method.isAnnotationPresent(PostConstruct.class)) { // Invoke the initialization method } } } }
This approach is common in dependency injection containers and lifecycle management. Because getMethods() only returns public methods, it ensures that the framework can legally invoke them without setting setAccessible(true). For non-public lifecycle methods, you would need getDeclaredMethods() and explicit access handling, which introduces additional security risks.
Compatibility and Version Considerations
getMethods() has been part of the Java reflection API since Java 1.1, so it is available in all modern Java versions. However, behavior has evolved slightly: static interface methods were not included until Java 8, and default methods were also introduced then. If you are working with older codebases, be aware that the returned array may differ based on the Java version. Always test your reflection code on the target runtime, especially if you rely on the presence or absence of specific inherited methods.
In summary, java getmethods — the getMethods() method — is a straightforward but powerful tool for runtime introspection. By understanding what it returns, how it differs from getDeclaredMethods(), and the performance implications of reflection, you can use it effectively in frameworks, testing tools, and any code that needs to discover public methods dynamically.