使用java反射将派生对象传递给想要超类的方法?
编辑:我不清楚。我必须使用反射,因为我是从命令行进行解释的。我正在做与我提供的代码示例相同的反射 希望这不是一个重复,因为这似乎是一个每天都要做的事情 我有一个类a和一个扩展了a的类B。如果我有一个类C中的方法,比如public void doSomething(a a),我如何使用反射将B对象传递到这个函数中?我想做(反射)等效于:使用java反射将派生对象传递给想要超类的方法?,java,inheritance,reflection,methods,Java,Inheritance,Reflection,Methods,编辑:我不清楚。我必须使用反射,因为我是从命令行进行解释的。我正在做与我提供的代码示例相同的反射 希望这不是一个重复,因为这似乎是一个每天都要做的事情 我有一个类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 sig
B b = new B(); //B inherits from A
C c = new C();
c.doSomething(b); // method signature is doSomething(A a);
我所做的(使用反射)是:
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();
所以
//***尝试从对象获取指定的方法
方法m=null;
//如果我们正在寻找该方法的无参数版本:
if(null==args)
{
尝试
{
m=obj.getClass().getMethod(methodToken,argTypes);
}
捕获(/*错误*/)
{
//做事
}
}
else//如果我们正在寻找接受参数的方法的版本
{
//我们必须进行这种类型的查找,因为我们的用户参数可能是
//方法所需的参数的子类。getMethod将不会
//在这种情况下找到匹配项。
尝试
{
布尔匹配发现=假;
c类=obj.getClass();
做
{//对于继承层次结构中的每个级别:
//使用正确的名称获取所有方法
//(匹配用户为方法提供的名称)
方法[]methodList=c.getMethods();
ArrayList matchingMethods=新的ArrayList();
对于(方法方法:方法列表)
{
if(meth.getName().equals(methodToken))
{
匹配方法。添加(meth);
}
}
//检查匹配的方法签名
用于(方法方法:匹配方法)
{
//获取方法下的参数类型
//调查需要时间。
类[]paramList=meth.getParameterTypes();
//确保签名具有所需的数字
//元素。如果不是,则这不是正确的方法。
if(paramList.length!=args.length)
{
继续;
}
//现在检查每个方法参数是否可以从
//由用户提供的参数给定的类型。这意味着
//我们正在检查每个用户的
//参数与相同,或是超类或
//在方法签名中找到的类型的superinterface
//(即,将用户参数传递给此
//方法。)如果其中一个不匹配,则这不是
//正确的方法,我们继续下一个。
布尔符号匹配=假;
对于(int i=0;i
希望它有助于某些人!您需要遵循Java语言规范第15.12节“方法调用表达式”中概述的相同过程,以找到在编译时可以找到的相同方法。简而言之,这比您想象的要复杂得多 一个简单的变体是用正确的名称检查所有方法(不要忘记
//*** 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
}
package so7691729;
import static org.junit.Assert.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class MethodCaller {
private boolean isCompatible(Method m, Object... args) {
Class<?>[] parameterTypes = m.getParameterTypes();
if (parameterTypes.length == args.length) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
// TODO: make primitive types equivalent to their boxed types.
return false;
}
}
}
} else {
// TODO: maybe handle varargs methods here
return false;
}
return true;
}
public Object call1(String fullyQualifiedMethodName, Object obj, Object... args) throws ClassNotFoundException, IllegalAccessException,
InvocationTargetException {
int lastDot = fullyQualifiedMethodName.lastIndexOf(".");
String className = fullyQualifiedMethodName.substring(0, lastDot);
String methodName = fullyQualifiedMethodName.substring(lastDot + 1);
Class<?> clazz = Class.forName(className);
for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
Set<String> sameNameMethods = Sets.newTreeSet();
Map<String, Method> compatibleMethods = Maps.newTreeMap();
for (Method method : c.getDeclaredMethods()) {
if (method.getName().equals(methodName)) {
sameNameMethods.add(method.toString());
if (isCompatible(method, args)) {
compatibleMethods.put(method.toString(), method);
}
}
}
if (compatibleMethods.size() > 1) {
throw new IllegalArgumentException("Multiple candidates: " + compatibleMethods.keySet());
}
if (compatibleMethods.size() == 1) {
return compatibleMethods.values().iterator().next().invoke(obj, args);
}
if (!sameNameMethods.isEmpty()) {
throw new IllegalArgumentException("Incompatible types for " + sameNameMethods);
}
}
throw new IllegalArgumentException("No method found.");
}
public Object call(String fullyQualifiedMethodName, Object obj, Object... args) {
try {
return call1(fullyQualifiedMethodName, obj, args);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
public String str(Object obj) {
return "object " + obj;
}
public String str(String str) {
return "string " + str;
}
public int add(int a, int b) {
return a + b;
}
@SuppressWarnings("boxing")
public int addObj(Integer a, Integer b) {
return a + b;
}
private void assertCallingError(String msg, String methodName, Object obj, Object... args) {
try {
call(methodName, obj, args);
fail();
} catch (IllegalArgumentException e) {
assertEquals(msg, e.getMessage());
}
}
@SuppressWarnings("boxing")
@Test
public void test() {
MethodCaller dummy = new MethodCaller();
assertEquals("object 1", call("so7691729.MethodCaller.str", dummy, 1));
assertCallingError("Multiple candidates: " + //
"[public java.lang.String so7691729.MethodCaller.str(java.lang.Object), " + //
"public java.lang.String so7691729.MethodCaller.str(java.lang.String)]", //
"so7691729.MethodCaller.str", dummy, "str");
assertCallingError("Incompatible types for [public int so7691729.MethodCaller.add(int,int)]", "so7691729.MethodCaller.add", dummy, 3, 4);
assertEquals(7, call("so7691729.MethodCaller.addObj", dummy, 3, 4));
assertCallingError("Incompatible types for [public int so7691729.MethodCaller.addObj(java.lang.Integer,java.lang.Integer)]", "so7691729.MethodCaller.addObj", dummy, "hello", "world");
}
}