Java 反射:从接口名称调用方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13611125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Reflection: Call method from Interface name
提问by Tapas Bose
I have have a name of an interface and I want to invoke a method defined by its concrete implemented class. So I took help of Java Reflection.
我有一个接口的名称,我想调用一个由其具体实现类定义的方法。所以我求助于Java Reflection。
The interface:
界面:
package tsb.learning.reflection;
public interface IAnyThing {
void doSomething();
}
It's implemented class:
它的实现类:
package tsb.learning.reflection;
public class AnyThing implements IAnyThing {
public void doSomething() {
System.out.println("JYM");
}
}
The implementation of InvocationHandler
:
的实施InvocationHandler
:
package tsb.learning.reflection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AnyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(proxy, args);
}
}
And the Controller:
和控制器:
package tsb.learning.reflection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Controller {
/**
* @param args
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
String interfaceName = "tsb.learning.reflection.IAnyThing";
ClassLoader classLoader = Class.forName(interfaceName).getClassLoader();
Class<?>[] interfaces = new Class<?>[] { Class.forName(interfaceName) };
InvocationHandler handler = new AnyInvocationHandler();
IAnyThing anyThing = (IAnyThing) Proxy.newProxyInstance(classLoader, interfaces, handler);
anyThing.doSomething();
}
}
But it is not working and I am getting the following exception:
但它不起作用,我收到以下异常:
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at tsb.learning.reflection.AnyInvocationHandler.invoke(AnyInvocationHandler.java:10)
at $Proxy0.doSomething(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at tsb.learning.reflection.AnyInvocationHandler.invoke(AnyInvocationHandler.java:10)
at $Proxy0.doSomething(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at tsb.learning.reflection.AnyInvocationHandler.invoke(AnyInvocationHandler.java:10)
at $Proxy0.doSomething(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at tsb.learning.reflection.AnyInvocationHandler.invoke(AnyInvocationHandler.java:10)
The exception is printing in console in loop, I need to stop the program.
例外是在控制台中循环打印,我需要停止程序。
Any information will be very helpful to me.
任何信息都会对我很有帮助。
回答by Peter Lawrey
Caused by: java.lang.reflect.InvocationTargetException
引起:java.lang.reflect.InvocationTargetException
This mean the method you called threw an exception. You need to look at the exception which appears after it and cause this one. It has nothing to do with how you called the method.
这意味着您调用的方法引发了异常。您需要查看出现在它之后的异常并导致此异常。这与您如何调用该方法无关。
I suspect you are getting a StackOverflowError
我怀疑你收到 StackOverflowError
// calls the same method on the same proxy which will recurse until you get an error.
return method.invoke(proxy, args);
Instead try calling a method on a real object to do something.
而是尝试在真实对象上调用方法来做某事。
public class AnyInvocationHandler implements InvocationHandler {
final IAnyThing iat;
public AnyInvocationHandler(IAnyThing iat) {
this.iat = iat;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// call the same method on a real object.
return method.invoke(iat, args);
}
}
BTW You can write
BTW 你可以写
Class interfaceClass = tsb.learning.reflection.IAnyThing.class;
ClassLoader classLoader = interfaceClass.getClassLoader();
Class<?>[] interfaces = new Class<?>[] { interfaceClass };
回答by mbelow
Inside your AnyInvocationHandler
, you could delegate the call to an instance of your AnyThing
:
在您的 中AnyInvocationHandler
,您可以将调用委托给您的一个实例AnyThing
:
public class AnyInvocationHandler implements InvocationHandler {
private AnyThing delegate = new AnyThing();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// to something useful here
[...]
// finally, invoke the method on implementation class.
return method.invoke(delegate, args);
}
}
回答by Saintali
The only method in IAnyThing
is doSomething()
, so I guess in the InvocationHandler
you know what the method is. Just put your implementation there. Also, beside doSomething()
you should also handle three methods inherited from java.lang.Object
:
中唯一的方法IAnyThing
是doSomething()
,所以我猜InvocationHandler
你知道这个方法是什么。只需将您的实现放在那里。此外,除了doSomething()
您还应该处理从java.lang.Object
以下继承的三个方法:
public static class AnyInvocationHandler implements InvocationHandler {
private static final Method doSomething;
static {
try {
doSomething = IAnyThing.class.getMethod("doSomething");
} catch (NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class)
return handleObjectMethod(proxy, method, args);
if (doSomething.equals(method)) {
doSomethingImpl();
return null;
}
throw new AbstractMethodError(method.toString());
}
private Object handleObjectMethod(Object proxy, Method method, Object[] args) {
switch (method.getName()) {
case "equals":
return proxy == args[0];
case "hashCode":
return System.identityHashCode(proxy);
case "toString":
return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
default:
throw new AssertionError();
}
}
private void doSomethingImpl() {
// implement....
}
}