【发布时间】:2011-12-03 06:03:46
【问题描述】:
编辑:我不清楚。我必须使用反射,因为我是从命令行解释的。我正在做与我提供的代码示例等效的反射。
希望这不是重复,因为这似乎是每天都想做的事情。
我有一个 A 类和一个扩展 A 的 B 类。如果我在 C 类中有一个方法,如 public void doSomething(A a),我如何使用反射将 B 对象传递给这个函数?我想做的(反射)相当于:
B b = new B(); //B inherits from A
C c = new C();
c.doSomething(b); // method signature is doSomething(A a);
我所做的(使用反射)是:
- 获取作为函数参数的对象。
- 获取参数的类
- 根据参数的类查找方法。
- 调用方法,传入参数 Objects。
如果我要将 A 对象传递给 C.doSomething(...),这将非常有用。但是,如果我试图将 B 对象传递给 C.doSomething(...) 它在第 3 步失败,并出现以下错误:
java.lang.NoSuchMethodException: C.doSomething(B)
让 C.doSomething 识别 B 是 A 的适当方法是什么? (使用 getDeclaredMethod(String name, Class... parameterTypes) 查找方法并将 B.class 作为参数类型传入时)
编辑:
我将发布我自己的解决方案,以防有人希望看到一种快速破解的方法来执行 Roland Illig 的建议。在这个例子中,我引用了这些预制变量:
String methodToken; //the name of the method
Object obj; //the object whose method we are trying to call
Object[] args; //the user given arguments for the method
Class[] argTypes; //the types of the args gotten by args[i].getClass();
所以...
//*** try to get the specified method from the object
Method m = null;
// if we are looking for a no-arg version of the method:
if(null == args)
{
try
{
m = obj.getClass().getMethod(methodToken, argTypes);
}
catch ( /*errors*/ )
{
// do stuff
}
}
else // if we are looking for a version of the method that takes arguments
{
// we have to do this type of lookup because our user arguments could be
// subclasses of the arguments required by the method. getMethod will not
// find a match in that case.
try
{
boolean matchFound = false;
Class c = obj.getClass();
do
{ // for each level in the inheritance hierarchy:
// get all the methods with the right name
//(matching the name that the user supplied for the method)
Method[] methodList = c.getMethods();
ArrayList<Method> matchingMethods = new ArrayList<Method>();
for( Method meth : methodList)
{
if(meth.getName().equals(methodToken))
{
matchingMethods.add(meth);
}
}
// check for a matching method signature
for( Method meth : matchingMethods)
{
// get the types of the arguments the method under
// investigation requires.
Class[] paramList = meth.getParameterTypes();
// make sure the signature has the required number of
// elements. If not, this is not the correct method.
if(paramList.length != args.length)
{
continue;
}
// Now check if each method argument is assignable from the
// type given by the user's provided arguments. This means
// that we are checking to see if each of the user's
// arguments is the same as, or is a superclass or
// superinterface of the type found in the method signature
//(i.e. it is legal to pass the user arguments to this
// method.) If one does not match, then this is not the
// correct method and we continue to the next one.
boolean signatureMatch = false;
for ( int i = 0; i < paramList.length; ++i)
{
if(paramList[i].isAssignableFrom( argTypes[i] ) )
{
signatureMatch = true;
}
else
{
continue;
}
}
// if we matched the signature on a matchingly named
// method, then we set the method m, and indicate
// that we have found a match so that we can stop
// marching up the inheritance hierarchy. (i.e. the
// containing loop will terminate.
if(true == signatureMatch)
{
m = meth;
matchFound = true;
break;
}
}
// move up one level in class hierarchy.
c = c.getSuperclass();
}
while(null != c && false == matchFound);
}
catch( /*errors*/)
{
// do stuff
}
}
// check that m got assigned
if(null == m)
{
System.out.println("From DO: unable to match method");
return false;
}
// try to invoke the method !!!!
try
{
m.invoke(obj, args);
}
catch ( /* errors */ )
{
// do stuff
}
希望它对某人有所帮助!
【问题讨论】:
-
这应该可以工作。如果
B是从A派生的,则它可以在任何需要A对象的地方使用。这就是多态性的意义所在。 -
问题是,没有方法
doSomething(B),只有doSomething(A)。既然没有完美匹配的方法,代码怎么知道它应该调用那个方法? -
注意:仔细阅读问题 - 它是关于如何通过反射找到正确的方法。
-
我必须使用反射,因为我正在制作命令行解释器。
-
很久以前我不得不这样做,我们最终遍历对象参数的继承树,直到找到匹配的签名。这适用于一个论点,但对于多个论点来说是淫秽的。请注意,这是在 JDK 1.2 的日子里,我绝对不建议将它用于现代 Java 编码。
标签: java inheritance reflection methods