在Java中,实例和类型转换(即(ClassName))如何在代理对象上工作?

lea*_*ner 8 java proxy dynamic-proxy

Java为给定接口生成代理类,并提供代理类的实例.但是当我们输入代理对象到我们的特定对象时,java如何在内部处理它?这被视为特殊情况吗?

例如,当我通过使用提供的接口中的方法传递接口Java创建的代理类来创建代理对象并且提供此类的对象(即)时,我有类OriginalClass并且它实现.如果我的理解是正确的,那么请你回答以下问题OriginalInterfaceOriginalInterfaceProxyClassProxyClass

  1. 当我输入我的类的强制转换对象时ProxyClass,OriginalClass这是有效的,但Java是如何允许的?在实例的情况下相同?
  2. 据我所知,Java仅使用方法创建代理类,但是当我尝试访问此对象的属性时会发生什么?
  3. 只有接口方法在代理中实现,但是当我尝试访问不在接口中且仅在类中提到的方法时会发生什么?

谢谢,学生

Boz*_*zho 11

Java不允许从代理转换为具体类.JDK代理(java.lang.reflect.Proxy)只是接口的代理.生成的代理是类型ProxyX(X是数字),如果您尝试将其转换为任何类,您将获得ClassCastException

因此,您的第2和第3个问题不相关 - 代理不受具体类的支持.为此,您可以使用其他代理机制 - CGLIB或javassist.它们使用ynamic子类,因此protected子类(代理)可以访问所有(和以上)字段和方法.


ric*_*chj 8

来自java.lang.reflect.InvocationHandler的API javadoc:

InvocationHandler是由代理实例的调用处理程序实现的接口.

动态代理实现了接口,但使用处理程序(OriginalClass)来提供方法的基本实现.

回答你的问题:

  1. 只要没有足够的信息来确定转换不能成功,编译器就会让你进行转换.在java.lang.reflect.Proxy的javadoc中描述了动态代理的转换和instanceof测试的运行时行为.如果与接口一起使用,则转换和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;
    }
}
Run Code Online (Sandbox Code Playgroud)

文章有很多有用的信息和示例代码.