简体   繁体   English

Java反射:接口名称中的调用方法

[英]Java Reflection: Call method from Interface name

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. 任何信息对我都会非常有帮助。

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 顺便说一句你可以写

Class interfaceClass = tsb.learning.reflection.IAnyThing.class;
ClassLoader classLoader = interfaceClass.getClassLoader();
Class<?>[] interfaces = new Class<?>[] { interfaceClass };

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);
    }
}

The only method in IAnyThing is doSomething() , so I guess in the InvocationHandler you know what the method is. IAnyThing唯一的方法是doSomething() ,所以我猜在InvocationHandler您知道该方法是什么。 Just put your implementation there. 只需将您的实现放在这里。 Also, beside doSomething() you should also handle three methods inherited from java.lang.Object : 另外,除了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....
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM