簡體   English   中英

Java反射:接口名稱中的調用方法

[英]Java Reflection: Call method from Interface name

我有一個接口的名稱,我想調用由其具體實現的類定義的方法。 因此,我接受了Java Reflection的幫助。

界面:

package tsb.learning.reflection;

public interface IAnyThing {

    void doSomething();
}

它是實現的類:

package tsb.learning.reflection;

public class AnyThing implements IAnyThing {

    public void doSomething() {
        System.out.println("JYM");
    }
}

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

和控制器:

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

但這不起作用,並且出現以下異常:

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)

例外是在控制台循環打印,我需要停止程序。

任何信息對我都會非常有幫助。

造成原因:java.lang.reflect.InvocationTargetException

這意味着您調用的方法引發了異常。 您需要查看在它之后出現的異常並引起該異常。 它與您如何調用該方法無關。

我懷疑您收到了StackOverflowError

// calls the same method on the same proxy which will recurse until you get an error.
return method.invoke(proxy, args);

而是嘗試在實際對象上調用方法以執行某些操作。

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

順便說一句你可以寫

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

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

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....
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM