Java:运行时方法解析
我正在通过解释器进行一些代码的动态调用,并且我正在进入方法解析的棘手难看的领域,如中所讨论的 选择方法的“简单”方法是当您知道所有参数的确切类型时,此时您可以使用。也许您必须检查方法的可访问性和类的超类/超接口 但这不包括以下任何一种情况,所以它是无用的:Java:运行时方法解析,java,reflection,overload-resolution,Java,Reflection,Overload Resolution,我正在通过解释器进行一些代码的动态调用,并且我正在进入方法解析的棘手难看的领域,如中所讨论的 选择方法的“简单”方法是当您知道所有参数的确切类型时,此时您可以使用。也许您必须检查方法的可访问性和类的超类/超接口 但这不包括以下任何一种情况,所以它是无用的: 装箱/取消装箱原语 亚型 瓦拉格斯 null参数(可以是任何类型,除非解释器另行知道;在编译时,通过将null强制转换到类/接口来消除任何歧义) 原语类型转换(不是Java的一部分,但在语言环境中是允许的——例如Rhino Javascri
- 装箱/取消装箱原语
- 亚型
- 瓦拉格斯
- null参数(可以是任何类型,除非解释器另行知道;在编译时,通过将null强制转换到类/接口来消除任何歧义)
- 原语类型转换(不是Java的一部分,但在语言环境中是允许的——例如Rhino Javascript,其中所有数字都是浮点型的,因此Java代码可能采用
,但调用者传入的数字可以是int
或int
)double
package com.example.test.reflect;
import java.lang.reflect.Method;
public class MethodResolutionTest {
public void compute(int i) { /* implementation... */ }
public void compute(Long l) { /* implementation... */ }
public void compute(Object obj) { /* implementation... */ }
public void compute(String... strings) { /* implementation... */ }
public static void main(String[] args) {
Class<?> cl = MethodResolutionTest.class;
/* these succeed */
findAndPrintMethod(cl, "compute", int.class);
findAndPrintMethod(cl, "compute", Long.class);
findAndPrintMethod(cl, "compute", Object.class);
findAndPrintMethod(cl, "compute", String[].class);
/* these fail */
findAndPrintMethod(cl, "compute", Integer.class);
findAndPrintMethod(cl, "compute", long.class);
findAndPrintMethod(cl, "compute", MethodResolutionTest.class);
findAndPrintMethod(cl, "compute", String.class, String.class);
}
private static void findAndPrintMethod(Class<?> objectClass,
String methodName, Class<?>... parameterTypes)
{
try {
Method method = findMethod(objectClass, methodName,
parameterTypes);
System.out.println(method.toString());
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private static Method findMethod(Class<?> objectClass,
String methodName, Class<?>[] parameterTypes)
throws SecurityException, NoSuchMethodException
{
return objectClass.getDeclaredMethod(methodName, parameterTypes);
}
}
package com.example.test.reflect;
导入java.lang.reflect.Method;
公共类方法解析测试{
公共void计算(int i){/*实现…*/}
公共void计算(长l){/*实现…*/}
公共void计算(对象obj){/*实现…*/}
公共void计算(字符串…字符串){/*实现…*/}
公共静态void main(字符串[]args){
类别cl=MethodResolutionTest.Class;
/*这些成功*/
findAndPrintMethod(cl,“计算”,int.class);
findAndPrintMethod(cl,“计算”,Long.class);
findAndPrintMethod(cl,“计算”,Object.class);
findAndPrintMethod(cl,“计算”,字符串[]。类);
/*这些失败了*/
findAndPrintMethod(cl,“计算”,Integer.class);
findAndPrintMethod(cl,“计算”,long.class);
FindPrintMethod(cl,“计算”,MethodResolutionTest.class);
findAndPrintMethod(cl,“计算”,String.class,String.class);
}
私有静态void findAndPrintMethod(类objectClass,
字符串方法名称,类…参数类型)
{
试一试{
Method=findMethod(对象类、方法名、,
参数类型);
System.out.println(method.toString());
}
捕获(安全异常e){
e、 printStackTrace();
}
捕获(无此方法例外){
e、 printStackTrace();
}
}
私有静态方法findMethod(类objectClass,
字符串方法名,类[]参数类型)
抛出SecurityException,NoSuchMethodException
{
返回objectClass.getDeclaredMethod(方法名,参数类型);
}
}
我在MVEL和属性方面取得了一些成功,但我记不起它是否能够分派方法调用
然而,您可能正在寻找完全不同的语言。鉴于问题的性质,我建议看看Groovy,它与Java的集成非常干净。Commons beanutils具有查找匹配方法的功能:
它适用于基本类型,但正如文档中所说,它有点不确定。您可能需要阅读并签出。它应该可以为您完成大部分繁重的工作。番石榴上的一位用户建议我查看
不幸的是,它也不能处理重载解析,至少目前不能。@Jonathon:我知道isAssignableFrom。我在处理子类型和装箱/拆箱时得到了一些自制的东西。然后我开始进入瓦拉格斯,它变得很糟糕,我想,“等等,我为什么要这么做?”所以我特别寻找一个已经存在的图书馆。(或者至少是一组好的预先存在的测试用例)否则我可以自己做,但这是一个很大的痛苦。除非你找到一个可爱的库,否则我认为你做的任何事情都会很难看,很难阅读。是的,我知道。如何吸引谷歌、甲骨文、IBM、Apache或其他公司的Java半神来制作一个好的非病毒开源库来实现这一点?这是Java反射的缺失部分,IMHO。我可以想出一些适合我自己的方法,但我认为无论是在正确性/文档记录/可维护性方面都远远不够完美。请注意,在
getMatchingAccessibleMethod
中,基本匹配是单向的-参数Long。class
将匹配foo(Long)
但是Long.TYPE
与foo(Long)
+1:@Bengt:发现Apache有一些工具,这让我松了一口气,也许不是我想要的,但至少是一些东西。嗯,出于各种原因,我“卡在”Java上,最大的一个原因是可维护性(添加不同的语言明显限制了我从其他开发人员那里获得帮助的能力)啊!太有希望了,但它有点不同——它解析泛型类型,但对方法解析没有任何作用。但至少这是一个开始,我敢打赌我可以诱使作者扩展它。