【问题标题】:Java - getting the signature of a method in an interface, and the same for its Proxy implementationJava - 在接口中获取方法的签名,其代理实现也是如此
【发布时间】:2009-10-21 09:08:08
【问题描述】:

我正在寻找一种方法来提取 Java 中签名的本质。原因是我想在我的 java.lang.reflect.Proxies 的 Map 中使用签名作为唯一键。

使用此代码:

public interface MyInterface {
  public int compute(String s);
}

...
public static void main (String... args) throws Exception {
  InvocationHandler handler = ...;
  MyInterface i = (MyInterface) Proxy.newProxyInstance(
      Beans.class.getClassLoader(),
      new Class<?>[] { MyInterface.class },
      handler);

  Method m1 = MyInterface.class.getMethod("compute", String.class);
  Method m2 = i.getClass().getMethod("compute", String.class);
  System.out.printf("%b%f", m1.equals(m2));
}

结果显然是假的。

此代码不是我将使用的代码,因为我需要在 InvocationHandler 中使用它,但我想知道关于代理实现和接口,获取 method.getName()method.getParameterTypes() 是否足够或者我应该使用method.getTypeParameters()method.getParameterAnnotations() 也一样?

简而言之:如何获得与接口及其 java.lang.reflect.Proxy 实现相同的方法签名?

【问题讨论】:

  • 您需要将代理存储在地图中吗?创建它们并不昂贵,可能不值得缓存它们。
  • 不,我不存储我的代理:只是方法,所以我避免了一个 loooooooong 开关。
  • 我的意思是,为什么不在每次需要时创建代理,而不是通过方法签名查找它们?

标签: java reflection proxy method-signature


【解决方案1】:

我认为您希望 Method 传入 InvocationHandler

package playtest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import static junit.framework.Assert.*;

interface MyInterface {
    void run();
    void about();
    void run(String j);
}


public class TestProxyClass {
    @Test
    public void testDeclaringClass() throws Exception {
        final Map<Method, Runnable> actions = new HashMap<Method, Runnable>();

        actions.put(MyInterface.class.getMethod("run"), new Runnable() {

            @Override
            public void run() {
                System.out.println("run");
            }

        } );
        actions.put(MyInterface.class.getMethod("run", String.class), new Runnable() {

            @Override
            public void run() {
                System.out.println("run string");
            }

        } );
        actions.put(MyInterface.class.getMethod("about"), new Runnable() {

            @Override
            public void run() {
                System.out.println("about");
            }

        } );

        MyInterface face = (MyInterface) Proxy.newProxyInstance(getClass().getClassLoader(), 
                new Class<?>[] { MyInterface.class }, new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        actions.get(method).run();
                        return null;
                    }

                } );

        face.run();
        face.about();
        face.run("Hello");
    }
}

【讨论】:

  • 有效!但我很困惑。使用您的代码,传递给调用的方法是 MyInterface 之一;与我的一样,传递给invoke 的方法是Proxied 类的方法之一,它与MyInterface 的方法不同。无论如何,我有我的答案,谢谢!
【解决方案2】:

Method.toGenericString的结果作为key呢?据我所知,它返回的字符串包括签名的所有详细信息。

另一个可能有用的是:Method m2 = i.getClass().getMethod("compute", String.class).getDeclaringClass().getMethod("compute", String.class);。这可能会导致 m1.equals(m2) 返回 true。

【讨论】:

  • toGenericString()(或toString()):否,因为 MyInterface.class.getMethod("compute") 中返回的方法给出了与 i.getClass().getMethod("计算”)第二个解决方案也无效,因为“声明类”返回代理类,而不是接口。
【解决方案3】:

我刚刚在执行此操作时遇到了代码错误,我使用了 name、genericReturnType 和 genericParameterTypes,但在使用代理时遇到了问题,因为我丢失了通用信息。

我切换到使用 name、returnType 和 parameterTypes 并且效果很好...

我也考虑过使用 declaringClass 但我删除了它并且不记得我是如何做到的......

【讨论】:

  • 对不起,这没有帮助:我已经使用过,但事实证明它不能正常工作。
猜你喜欢
  • 1970-01-01
  • 2021-10-31
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-06
相关资源
最近更新 更多