2012-11-28 39 views
1

我有一個接口的名稱,我想調用由其具體實現的類定義的方法。所以我接受了Java Reflection的幫助。Java反射:從接口名稱調用方法

接口:

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) 

唯一的例外是在控制檯打印的循環,我需要停止該程序。

任何信息對我都很有幫助。

回答

3

造成的: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); 
    } 
} 

BTW你可以寫

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

謝謝。所以方法'AnyInvocationHandler#invoke'的實現可以嗎? –

+0

@TapasBose我重寫的方式是,是的。 ;) –

+0

感謝您的代碼片段正在工作。但是如果我不知道實施課程,在這裏AnyThing,那我該怎麼做?其實它是一個演示應用程序。實際上我不知道哪個類實現了它。 –

1

裏面你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); 
    } 
} 
1

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

} 
+0

謝謝,你的例子是有幫助的,但它不是真實的案例。在真實情況下,我只有接口名稱,我從RMI中獲得了它,並且需要調用該接口的一個方法。 –

+1

你是否告訴我你想在不知道它是什麼的情況下實現一個接口,甚至沒有具體的實現類?問問你自己,如果你從RMI收到'java.util.Collection'會發生什麼。你打算模擬一個'ArrayList'或'HashSet'或'LinkedBlockingQueue'或....?現在有數以千計的這些接口。 – Saintali