Even though reflection is used widely in popular libraries such as Spring and Jackson, direct use of reflection is thankfully pretty rare, as it can be challenging to make robust. One issue with reflection is that it can work in ways that break typical assumptions about Java. For example, looking up a method using reflection works very differently from the way Java finds and calls a method in normal code.
In object-oriented programming languages, we’re used to the idea that a class
has its own methods plus all the methods from the classes it extends, as long
as those methods are
public. This works in Java reflection as
well. For an example, try this block of code:
This will print a list of method names that includes methods such as
wait that are defined in
Object.class and are inherited by
In object-oriented programming languages, we’re also used to the idea that a
class has an “is-a” relationship with the classes it extends, so that for all
purposes it can be used anywhere its parent classes can be used. A
Collection, so anywhere we can use a
Collection, we can use a
including as a parameter to a method that asks for a
When we invoke methods using Java reflection, this is-a relationship holds.
But when looking up a method using reflection, Java is more strict.
Class.getMethod and its cousins (
getDeclaredConstructor) will only match a method if the exact types
of the parameters are used. This has been true basically forever in Java,
as evidenced by this discussion.
An example is as follows:
getMethod() call in the try block will fail. Even though List is a
subclass of Collection, so that it would be valid Java to pass a List object to
this method, reflection won’t find it because the parameter type match is not
Unfortunately, when we’re using reflection, we tend to be looking up methods with parameters that match object instances we’re currently holding. We don’t know what type those objects are going to be at compile time (or we wouldn’t be using reflection), so there isn’t a simple solution to this problem.
There may be a more elegant workaround out there, but this at least does the job for me:
This code looks through all the methods whose name matches. For each method, it determines if the number of parameters match, and if so, it determines whether the type of each parameter could be legally cast to the type the method is expecting. If all parameters pass, then the method is valid and it is returned to the caller. If there’s a mismatch, it goes on to the next method.
With this method available, we can write:
addAll takes 1 parameter and
Collection is assignable from
List, we will find the correct match and be able to invoke it.