2010-05-03 67 views
7

Java爲給定接口生成代理類並提供代理類的實例。但是當我們將代理對象轉換爲我們特定的對象時,java如何在內部處理它?這是否被視爲特殊情況?在Java中,類型轉換的實例(即(ClassName))如何處理代理對象?

例如,我有OriginalClass類,它實現OriginalInterface,當我通過傳遞OriginalInterface接口的Java創建的代理類使用方法ProxyClass在所提供的接口創建代理對象,並提供此類(即ProxyClass)的對象。如果我的理解是正確的,那麼能否請您回答以下查詢

  1. 當我類型轉換的ProxyClass反對我OriginalClass類工作的,但Java是如何使這個?同樣的情況下?
  2. 由於我的知識Java只使用方法創建代理類,但是當我嘗試訪問此對象上的屬性時會發生什麼?
  3. 只有接口方法在代理中得到實現,但是當我嘗試訪問不在接口中且僅在類中提及的方法時會發生什麼?

感謝, 學生

+1

你是否確實將你的代理強制轉換爲OriginalClass?在我的理解中,如果你爲OriginalInterface創建了代理,那麼你不應該能夠轉換成OriginalClass – 2010-05-03 10:26:15

回答

11

的Java是不允許從代理鑄造的具體類。 JDK代理(java.lang.reflect.Proxy)只是接口的代理。產生的代理是ProxyX型(X爲數字)的,如果你嘗試將其轉換爲任何類,你會得到ClassCastException

因此你的第二和第三個問題是不相關的 - 代理未後盾一個具體的類。爲了達到這個目的,你可以使用其他代理機制 - CGLIB或javassist。它們使用動態子類化,因此所有protected(及以上)字段和方法都可以訪問子類(代理)。

+0

非常感謝您的快速回復。 Java不允許投射到具體的類。 – learner 2010-05-03 11:23:25

7

從java.lang.reflect.InvocationHandler的API的javadoc:

的InvocationHandler是代理實例的調用處理程序實現的接口。

動態代理實現接口,但使用處理程序(OriginalClass)提供方法的基本實現。

回答您的問題:

  1. 編譯器將讓你投,只要它沒有足夠的信息可以肯定,中投也不能成功。在javadoc中爲java.lang.reflect.Proxy描述了動態代理的cast和instanceof測試的運行時行爲。如果與接口一起使用,Casts和instanceof測試將會成功,但如果與類一起使用則不會。
  2. 您不能使用動態代理訪問任何屬性,因爲它實現了接口,它不會擴展處理程序類。
  3. 您不能使用動態代理訪問未在接口中聲明的任何方法,因爲它實現了接口,它不擴展處理程序類。

在動態代理的實現中(例如在執行invoke(...)方法),您可以使用反射訪問處理程序的成員。

下面是一些測試代碼,我來檢查我的回答:

// package ...; 

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 

import junit.framework.Assert; 

import org.junit.Test; 

public class TestDynamicProxy 
{ 
    @Test 
    public void testCast() throws Exception { 
     Foo foo = (Foo) TestProxy.newInstance(new FooImpl()); 
     foo.bar(null); 

     System.out.println("Class: " + foo.getClass()); 
     System.out.println("Interfaces: " + foo.getClass().getInterfaces()); 

     Assert.assertNotNull(foo); 
     Assert.assertTrue(foo instanceof Foo); 
     Assert.assertFalse(foo instanceof FooImpl); 
    } 
} 

interface Foo 
{ 
    Object bar(Object obj) throws Exception; 
} 

class FooImpl implements Foo 
{ 
    public Object bar(Object obj) throws Exception { 
     return null; 
    } 
} 

class TestProxy implements java.lang.reflect.InvocationHandler 
{ 
    private final Object obj; 

    public static Object newInstance(Object obj) { 
     return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new TestProxy(obj)); 
    } 

    private TestProxy(Object obj) { 
     this.obj = obj; 
    } 

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { 
     Object result; 

     try { 
      result = m.invoke(obj, args); 
     } 
     catch (InvocationTargetException e) { 
      throw e.getTargetException(); 
     } 
     catch (Exception e) { 
      throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); 
     } 

     return result; 
    } 
} 

article有很多有用的信息和示例代碼。

+0

非常感謝。您的信息非常有用。 – learner 2010-05-03 11:24:38

相關問題