简体   繁体   English

Java Class.getMethods() 对覆盖方法的行为

[英]Java Class.getMethods() behavior on overridden methods

While writing a simple JSON serialiser using reflection in Java I was caught off guard by the behavior of Class.getMethods().在 Java 中使用反射编写一个简单的 JSON 序列化程序时,我被 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.如果覆盖方法的返回类型扩展了覆盖方法的返回类型,则 Java Class.getMethods() 似乎返回覆盖方法和覆盖方法。
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). A.class.getMethods()按预期返回两个方法的数组,但是B.class.getMethods()返回一个由 3 个方法组成的数组(这对我来说有点反直觉)。 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.在这 3 个中,1 对应于预期的y() ,但其余两个分别对应于具有返回类型A的原始x()和具有返回类型Bx()的覆盖版本。 This struck me as a little odd to have but the original x() in the array since its not accessible from anywhere.这让我觉得有点奇怪,但数组中的原始x()因为它无法从任何地方访问。 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?有没有简单的方法来获取类方法的最专业版本的列表,而无需手动检查覆盖的方法并将它们过滤掉?

My understanding is that if you filter out methods for which isBridge() returns true , the unwanted method should go away.我的理解是,如果您过滤掉isBridge()返回true的方法,那么不需要的方法应该 go 消失。

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).这是 Java 如何实现协变返回类型的人工制品(桥方法也用于 generics,但这似乎与您的用例无关)。

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. B的所有三种方法都标记为非桥接和非合成。 However, if I create a non-abstract class C implementing B , its A x() is marked as both bridge and synthetic.但是,如果我创建一个实现B的非抽象 class C ,则它A x()被标记为桥接和合成。

What you have is called "covariant return".您所拥有的称为“协变回报”。

As aix points out, it seems you have to deal with bridge methods.正如 aix 指出的那样,您似乎必须处理桥接方法。 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)阅读: http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html (忽略关于泛型的文本)和这个: GetDeclaredMethods 中的问题(java)

One way is to say: B.class.getDeclaredMethods() , however, this will return only the methods declated in B. So, if you have C extends B implements A, C.class.getDeclaredMethods() wont return the methods that you haven't overridden. One way is to say: B.class.getDeclaredMethods() , however, this will return only the methods declated in B. So, if you have C extends B implements A, C.class.getDeclaredMethods() wont return the methods that you没有被覆盖。

if you want to iterate, good way to do that is如果你想迭代,这样做的好方法是

for (Method m: B.class.getMethods()) {
  if (m.getDeclaringClass() == Object.class || m.declaringClass() == A.class) 
    continue;
  // otherwise do some stuff
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM