While writing a simple JSON serialiser using reflection in Java I was caught off guard by the behavior of Class.getMethods(). It appears that Java Class.getMethods() returns both overriding and overridden methods if the return type of the overriding method extends that of the overridden method.
So for example given the interfaces:
static interface A {
A x();
A y();
}
static interface B extends A {
B x();
A y();
}
A.class.getMethods()
returns and array of two methods as expected
however B.class.getMethods()
returns an array of 3 methods (which to me was a little counter intuitive).
Of the 3, 1 corresponds to the y()
as expected but the remaining two correspond to the original x()
with return type A
and the overriding version of x()
with return type B
respectively. This struck me as a little odd to have but the original x()
in the array since its not accessible from anywhere. Anyway my question is this:
Is there and easy way to get a list of only the most specialised versions of a class's methods without resorting to manually checking for overridden methods and filtering them out?
Yes. It is possible for overridden methods to have different return type .
Reflection can be used to determine if a method is overridden. The code is a little bit tricky. For instance, you need to be aware that you have a runtime class that is a subclass of the class that overrides the method. You are going to see the same runtime classes over and over again.
Instance Methods The ability of a subclass to override a method allows a class to inherit from a superclass whose behavior is "close enough" and then to modify behavior as needed. The overriding method has the same name, number and type of parameters, and return type as the method that it overrides.
Instance methods can be overridden only if they are inherited by the subclass. A method declared final cannot be overridden. A method declared static cannot be overridden but can be re-declared. If a method cannot be inherited, then it cannot be overridden.
My understanding is that if you filter out methods for which isBridge()
returns true
, the unwanted method should go away.
It is an artefact of how Java implements covariant return types (bridge methods are also used for generics, but that doesn't appear relevant to your use case).
edit Interestingly enough, while this works for classes, it doesn't seem to work for interfaces. All three methods of B
are marked as non-bridge and non-synthetic. However, if I create a non-abstract class C
implementing B
, its A x()
is marked as both bridge and synthetic.
What you have is called "covariant return".
As aix points out, it seems you have to deal with bridge methods. Read this: http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html (ignore the text about generics) and this: Problem in the GetDeclaredMethods (java)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With