2010-05-03 2 views
7

Java는 주어진 인터페이스에 대한 프록시 클래스를 생성하고 프록시 클래스의 인스턴스를 제공합니다. 그러나 우리가 특정 객체에 프록시 객체를 형변환 할 때 자바가 내부적으로 이것을 처리하는 방법은 무엇입니까? 이것은 특별한 시나리오로 취급됩니까? 예를 들어Java에서 인스턴스의 인스턴스와 캐스트 (예 : (ClassName))가 프록시 객체에서 작동하는 방식은 무엇입니까?

는 I 클래스 OriginalClass 있고 그것은 I 제공된 인터페이스 OriginalInterface 인터페이스 자바 생성 프록시 클래스의 방법을 사용 ProxyClass 전달하여 프록시 객체를 생성 할 때, OriginalInterface 구현이 클래스 (즉. ProxyClass)의 목적을 제공한다. 나의 이해가 올 경우에 당신은 쿼리

    나는 내 수업 OriginalClass이 작품에 ProxyClass의 객체를 캐스팅 입력
  1. 하지만, 자바이 허용하는 방법을 다음에 답하시기 바랍니다 수 있습니까? instace의 경우에도 마찬가지입니까? 내 지식 자바로
  2. 만의 방법으로 프록시 클래스를 생성하지만이 개체의 속성에 액세스하려고 할 때 어떤 일이?
  3. 만 인터페이스 방법은 프록시 구현지고 있지만 클래스에 언급되지 않은 인터페이스 만하는 방법을 액세스하려고하면 어떻게됩니까?

감사합니다, 학생 자바 구체적인 클래스에 프록시에서 캐스팅 허용하지 않습니다

+1

프록시를 OriginalClass로 전송하는 것이 효과적일까요? OriginalInterface에 대한 프록시를 만든 경우 내 이해에서 OriginalClass로 캐스팅하지 않아야합니다. –

답변

11

. JDK 프록시 (java.lang.reflect.Proxy)는 인터페이스의 프록시 일뿐입니다. 결과 프록시는 유형이 ProxyX (X는 숫자)이고, 어떤 클래스로도 캐스팅하려고하면 ClassCastException

따라서 두 번째와 세 번째 질문은 관련이 없습니다. 프록시는 지원되지 않습니다. 구체적인 클래스. 이를 위해 CGLIB 또는 javassist와 같은 다른 프록시 메커니즘을 사용할 수 있습니다. 그들은 ynamic 서브 클래 싱을 사용하기 때문에 서브 클래스 (프록시)는 모두 protected (이상의) 필드와 메소드에 액세스 할 수 있습니다. java.lang.reflect.InvocationHandler에 대한 API의 javadoc에서

+0

빠른 답장을 보내 주셔서 감사합니다. Java는 구체적인 클래스로 캐스트 할 수 없습니다. – learner

7

:

의 InvocationHandler는 프록시 인스턴스의 호출 핸들러가 구현하는 인터페이스입니다.

동적 프록시는 인터페이스를 구현하지만 처리기 (OriginalClass)를 사용하여 메서드의 기본 구현을 제공합니다.

귀하의 질문에 대답하려면 :

  1. 컴파일러는 당신이 한이 캐스트가 성공할 수 없음을 확신 할 수있는 충분한 정보를 가지고 있지 않기 때문에 캐스팅하게됩니다. 동적 프록시에 대한 형변환 및 instanceof 테스트의 런타임 동작은 java.lang.reflect.Proxy 용 javadoc에 설명되어 있습니다. 캐스트 및 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

관련 문제