2010-05-03 123 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

相关问题