如何在Java中检查方法是否在运行时存在?

25

如何检查Java类中是否存在某个方法?使用 try {...} catch {...} 语句是否是良好的编程实践?


你是否在使用反射?否则,我不确定你在问什么... - Neil
try/catch 与方法存在有什么关系?除非你指的是像 Iterator 接口这样的情况,其中对于 remove 的实现可以抛出 UnsupportedOperationException - Ken Wayne VanderLinde
1
你在谈论哪种现有方法的检查?反射吗? - Jaka
1
我正在尝试查看一个可能不存在的所需方法是否存在,以便我知道是否可以调用它。我想我可以将调用放在 try catch 中,并在方法不存在时捕获错误。如果不明显,我并不是一个Java专业人士! - jrtc27
7个回答

30

我猜您想要检查方法doSomething(String, Object)

您可以尝试以下方法:

boolean methodExists = false;
try {
  obj.doSomething("", null);
  methodExists = true;
} catch (NoSuchMethodError e) {
  // ignore
}

这种方法行不通,因为方法将在编译时解析。

你需要使用反射来实现。如果你可以访问要调用的方法的源代码,最好创建一个带有要调用的方法的接口。

[更新]额外的信息是:可能存在两个版本的接口,一个是旧的(没有想要的方法),另一个是新的(有想要的方法)。基于此,我建议采取以下措施:

package so7058621;

import java.lang.reflect.Method;

public class NetherHelper {

  private static final Method getAllowedNether;
  static {
    Method m = null;
    try {
      m = World.class.getMethod("getAllowedNether");
    } catch (Exception e) {
      // doesn't matter
    }
    getAllowedNether = m;
  }

  /* Call this method instead from your code. */
  public static boolean getAllowedNether(World world) {
    if (getAllowedNether != null) {
      try {
        return ((Boolean) getAllowedNether.invoke(world)).booleanValue();
      } catch (Exception e) {
        // doesn't matter
      }
    }
    return false;
  }

  interface World {
    //boolean getAllowedNether();
  }

  public static void main(String[] args) {
    System.out.println(getAllowedNether(new World() {
      public boolean getAllowedNether() {
        return true;
      }
    }));
  }
}

这段代码测试接口中是否存在getAllowedNether方法,所以实际对象是否有该方法并不重要。

如果需要非常频繁地调用getAllowedNether方法,并且由于此原因而遇到性能问题,那么我将不得不考虑更高级的答案。但目前这个答案应该可以满足要求。


这个方法不在我的代码中,而是在一个链接的jar包中 - 这对它有用吗? - jrtc27
你能说出它是哪个方法吗?这个方法来自于一个接口吗?那么你可以使用instanceof运算符来查询它的存在。 - Roland Illig
编译器将遍历您指定的JAR包并查找所有方法,如果找不到某些内容,它将显示错误消息。 - Jaka
是的,这是一个接口 - 如果有帮助的话,我正在尝试查看https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/World.java中是否存在getAllowNether()方法(旧版本缺少它)。 - jrtc27
非常抱歉测试这个东西花了这么长时间!不管怎样,我可以确认这个有效,所以谢谢你。在我的情况下,它并不是瓶颈(真的),我确定我做的其他事情非常低效! - jrtc27
显示剩余3条评论

5

4

3
我会使用单独的方法来处理异常,并进行空值检查以检查该方法是否存在。
例如:if (null != getDeclaredMethod(obj, "getId", null)),然后进行你的操作...
private Method getDeclaredMethod(Object obj, String name, Class<?>... parameterTypes) {
    // TODO Auto-generated method stub
    try {
        return obj.getClass().getDeclaredMethod(name, parameterTypes);
    } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
} 

1
罗兰德·伊利格是正确的,但我想补充一个例子,说明如何使用Class.getMethod检查是否存在需要参数的方法。如果您要访问私有方法,也可以使用Class.getDeclaredMethod
class World {
    public void star(String str) {}
    private void mars(String str) {}
}
try {
    World.class.getMethod("star", String.class);
    World.class.getDeclaredMethod("mars", String.class);
} catch (Exception e) {}

1
如果您的项目中使用了Spring,您可以检查ReflectionUtil.findMethod(..)。如果方法不存在或不符合您的要求,则它将返回null。文档

0

其他解决方案:

public static <O> boolean existsMethod(final String methodName, final O o) {
    return Stream.of(o.getClass().getMethods()).map(Method::getName).anyMatch(methodName::equals);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接