2010-05-03 13 views
7

Java genera una clase proxy para una interfaz determinada y proporciona la instancia de la clase proxy. Pero cuando escribimos el objeto proxy para nuestro objeto específico, ¿cómo lo maneja Java internamente? ¿Esto es tratado como un escenario especial?En Java, ¿cómo funciona la instancia de y el tipo de conversión (es decir, (ClassName)) en el objeto proxy?

Por ejemplo I tienen clase OriginalClass e implementa OriginalInterface, cuando creo objeto proxy mediante el paso OriginalInterface interfaz Java creado clase de proxy ProxyClass utilizando métodos en la interfaz proporcionada y proporciona objeto de esta clase (es decir. ProxyClass). Si mi interpretación es correcta entonces se puede por favor responda a las preguntas siguientes

  1. cuando escribo convertir objeto de ProxyClass a mi clase OriginalClass esto funciona, pero la forma de Java está permitiendo esto? Lo mismo en caso de instace de?
  2. Según mis conocimientos, Java crea una clase proxy solo con los métodos, pero ¿qué ocurre cuando intento acceder a los atributos de este objeto?
  3. Solo los métodos de interfaz se implementan en proxy, pero ¿qué sucede cuando intento acceder a un método que no está en la interfaz y que solo se menciona en la clase?

Gracias, Estudiante

+1

¿Está seguro de que el envío de su proxy a OriginalClass funciona? Según tengo entendido, si creó el proxy para OriginalInterface, no podrá realizar el envío a OriginalClass –

Respuesta

11

Java no está permitiendo que la fundición de un proxy para una clase concreta. Los proxies JDK (java.lang.reflect.Proxy) son solo proxies de una interfaz. El proxy resultante es del tipo ProxyX (X es un número), y si intenta enviarlo a cualquier clase obtendrá ClassCastException

Por lo tanto, sus preguntas segunda y tercera no son relevantes: el proxy no está respaldado por una clase concreta. Para lograr esto, puede usar otros mecanismos de proxy: CGLIB o javassist. Usan subclases ynamic, por lo que todos los campos y métodos protected (y superiores) son accesibles para la subclase (proxy).

+0

Muchas gracias por su rápida respuesta. Java no permite lanzar a la clase concreta. – learner

7

De los javadocs API para java.lang.reflect.InvocationHandler:

InvocationHandler es la interfaz implementada por el controlador de la invocación de una instancia de proxy.

El proxy dinámico implementa la interfaz, pero utiliza el controlador (OriginalClass) para proporcionar las implementaciones básicas de los métodos.

para responder a sus preguntas:

  1. El compilador le permitirá lanzas con tal de que no tiene suficiente información para estar seguro de que el reparto no puede tener éxito. El comportamiento en el tiempo de ejecución de las pruebas de conversión y de instancia para proxies dinámicos se describe en javadoc para java.lang.reflect.Proxy. Las pruebas de instancia e instancia tendrán éxito si se usan con interfaces, pero no si se usan con clases.
  2. No puede acceder a ningún atributo utilizando el proxy dinámico porque implementa la interfaz, no extiende la clase de controlador.
  3. No puede acceder a ningún método no declarado en la interfaz utilizando el proxy dinámico porque implementa la interfaz, no extiende la clase de controlador.

Dentro de la implementación del proxy dinámico (por ejemplo, en la implementación de la invocación (...) método) puede acceder a los miembros del controlador utilizando la reflexión.

Aquí hay algo de código de prueba que he utilizado para comprobar mi respuesta:

// 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; 
    } 
} 

Este article tiene una gran cantidad de información útil y código de ejemplo.

+0

Muchas gracias. Su información es muy útil. – learner

Cuestiones relacionadas