Java:如何查找是否从基类重写了一个方法?

如何查明子类是否覆盖了某个方法?

例如,

public class Test { static public class B { public String m() {return "From B";}; } static public class B1 extends B { } static public class B2 extends B { public String m() {return "from B2";}; } /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) { B b1 = new B1(); System.out.println("b1 = " + b1.m()); B b2 = new B2(); System.out.println("b1 = " + b2.m()); } } 

给定B的一个实例,我怎么知道任何派生类是否有像B2这样的重写方法m()?

更新:我的问题不明确。 实际上,我试图在不诉诸反思的情况下询问是否可行。 这种检查是在一个紧凑的循环中完成的,它用于性能破解以节省一些CPU周期。

我认为到目前为止的答案是假设你有一个方法,并试图确定是否在类中重写该方法。

但是,问的实际问题是“给定一个B的实例,我如何知道任何派生类是否覆盖了方法m(),如B2?”

使用标准Java方法是不可能的,因为Java在引用之前不会加载类。 例如,假设您从网络上的jar(或许多jar)加载了URL类加载器。 Java不知道那些联网的jar文件中包含哪些类,更不用说它们是否碰巧覆盖了特定的方法。

我认为我已经看到Apache公共中的实用程序会尝试详尽地搜索类加载器的层次结构来组合所有可用类的列表,但这听起来对我来说是一个非常糟糕的主意。 首先,它将为JVM中的每个类触发每个静态初始化程序块。

有一些设施,比如服务提供程序接口,可以在jar的META-INF目录中列出实现某个接口的类名,也许你应该看看那条路由。

此问题有助于演示如何获取该方法所属的类的信息:

如何快速确定是否在Java中重写了方法

 class.getMethod("myMethod").getDeclaringClass(); 
  public static boolean isMethodOverrriden(Method myMethod) { Class declaringClass = myMethod.getDeclaringClass(); if (declaringClass.equals(Object.class)) { return false; } try { declaringClass.getSuperclass().getMethod(myMethod.getName(), myMethod.getParameterTypes()); return true; } catch (NoSuchMethodException e) { return false; } } 

改进Pavel Savara的post,这是我的方法版本,也适用于接口:

 public static boolean isMethodOverrriden(final Method myMethod) { Class declaringClass = myMethod.getDeclaringClass(); if (declaringClass.equals(Object.class)) { return false; } try { declaringClass.getSuperclass().getMethod(myMethod.getName(), myMethod.getParameterTypes()); return true; } catch (NoSuchMethodException e) { for (Class iface : declaringClass.getInterfaces()) { try { iface.getMethod(myMethod.getName(), myMethod.getParameterTypes()); return true; } catch (NoSuchMethodException ignored) { } } return false; } } 

这是我的解决方案,它是用Kotlin (JVM语言)编写的。

 //See: http://www.tutorialspoint.com/java/java_overriding.htm inline fun Method.isOverridableIn(cls: Class<*>): Boolean { if (!isOverridable) return false if (!isSubclassVisible) return false if (!declaringClass.isAssignableFrom(cls)) return false if (isPublic) return true if (isPackageVisible && cls.getPackage() == declaringClass.getPackage()) return true return false } private fun Method.areParametersCovariant(other: Method): Boolean { if (getParameterTypes() == null && other.getParameterTypes() == null) return true if (getParameterTypes() == null || other.getParameterTypes() == null) return false val myPrmTypes = getParameterTypes()!! val otherPrmTypes = other.getParameterTypes()!! if (myPrmTypes.size != otherPrmTypes.size) return false for (i in myPrmTypes.indices) if (!(otherPrmTypes[i].isAssignableFrom(myPrmTypes[i]))) return false return true } private fun Method.areParametersTheSameAs(other: Method): Boolean { if (getParameterTypes() == null && other.getParameterTypes() == null) return true if (getParameterTypes() == null || other.getParameterTypes() == null) return false val myPrmTypes = getParameterTypes()!! val otherPrmTypes = other.getParameterTypes()!! if (myPrmTypes.size != otherPrmTypes.size) return false for (i in myPrmTypes.indices) if (otherPrmTypes[i] != myPrmTypes[i]) return false return true } private fun Method.isReturnTypeCovariant(other: Method): Boolean { if (getReturnType() == null && other.getReturnType() == null) return true if (getReturnType() == null || other.getReturnType() == null) return false return other.getReturnType()!!.isAssignableFrom(getReturnType()!!) } private fun Method.isReturnTypeTheSameAs(other: Method): Boolean { if (getReturnType() == null && other.getReturnType() == null) return true if (getReturnType() == null || other.getReturnType() == null) return false return other.getReturnType() == getReturnType() } fun Method.findBridgeMethod(): Method? { if (isBridge()) return null return declaringClass.getDeclaredMethods().find { it != this && isBridge() && it.getName() == getName() && isReturnTypeCovariant(it) && areParametersCovariant(it) } } fun Method.isOverridenBy(other: Method): Boolean { val bridge = findBridgeMethod() if (bridge != null) return bridge!!.isOverridenBy(other) return getName() == other.getName() && isOverridableIn(other.declaringClass) && !other.isAccessMoreRestrictiveThan(this) && isReturnTypeTheSameAs(other) && areParametersTheSameAs(other); } fun Method.findOverridenMethod() = findOverridenMethodIn(declaringClass) private fun Method.findOverridenMethodIn(cls: Class<*>): Method? { val superclasses = arrayListOf(cls.superclass) cls.getInterfaces().forEach { superclasses.add(it) } for (superclass in superclasses) { if (superclass == null) continue var overriden = superclass.getDeclaredMethods().find { it.isOverridenBy(this) } if (overriden != null) return overriden overriden = findOverridenMethodIn(superclass) if (overriden != null) return overriden } return null; } //Workaround for bug KT-3194 //See: http://youtrack.jetbrains.com/issue/KT-3194 inline val Class<*>.superclass: Class<*>? get() = (this as Class).getSuperclass() inline val Member.isFinal: Boolean get() = Modifier.isFinal(getModifiers()) inline val Member.isPrivate: Boolean get() = Modifier.isPrivate(getModifiers()) inline val Member.isStatic: Boolean get() = Modifier.isStatic(getModifiers()) inline val Member.isPublic: Boolean get() = Modifier.isPublic(getModifiers()) inline val Member.isAbstract: Boolean get() = Modifier.isAbstract(getModifiers()) inline val Member.declaringClass: Class<*> get() = getDeclaringClass() inline fun Member.isAccessMoreRestrictiveThan(other: Member) = restrictionLevel > other.restrictionLevel private inline val Member.restrictionLevel: Int get() = when { isPrivate -> 0 isProtected -> 2 isPublic -> 3 else -> 1 //No scope modifiers = package private } //Note: Does not consider the declaring class "inheritability" inline val Method.isOverridable: Boolean get() = !isFinal && !isPrivate && !isStatic inline val Member.isPackageVisible: Boolean get() = !isPrivate inline val Member.isSubclassVisible: Boolean get() = isPublic || isProtected 

它与Java 100%兼容,所以我想它可以轻松翻译。 从理论上讲它应该处理所有重写的例子,例如generics,范围,不兼容的签名等。我希望这会有所帮助!

Java的reflectionAPI有一个Method类,它有一个名为getDeclaringClass()的方法。 这可能适用于您的需求。 这是API:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/Method.html#getDeclaringClass()

 private static boolean isMethodImplemented(Object obj, String name) { try { Class clazz = obj.getClass(); return clazz.getMethod(name).getDeclaringClass().equals(clazz); } catch (SecurityException e) { log.error("{}", e); } catch (NoSuchMethodException e) { log.error("{}", e); } return false; } 

java支持Annotations。 如果您不确定是否从基类重写了实现的方法。

只需在子类中使用方法启动之前使用@Override关键字。

如果该方法真的可以覆盖方法,那么它将编译正常。 否则会给出错误。

简单:)