java.lang.reflect.InvocationHandler の API javadoc から:
InvocationHandler は、プロキシ インスタンスの呼び出しハンドラによって実装されるインターフェイスです。
動的プロキシはインターフェースを実装しますが、ハンドラー (OriginalClass) を使用してメソッドの基本実装を提供します。
質問に答えるには:
- コンパイラは、キャストが成功しないことを確認するのに十分な情報がない限り、キャストを許可します。動的プロキシのキャストおよび instanceof テストの実行時の動作については、java.lang.reflect.Proxy の javadoc で説明されています。キャストと instanceof テストは、インターフェイスで使用すると成功しますが、クラスで使用すると成功しません。
- 動的プロキシはインターフェイスを実装し、ハンドラ クラスを拡張しないため、動的プロキシを使用して属性にアクセスすることはできません。
- 動的プロキシを使用してインターフェイスで宣言されていないメソッドにアクセスすることはできません。これは、インターフェイスを実装し、ハンドラー クラスを拡張しないためです。
動的プロキシの実装内 (たとえば、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;
}
}
この記事には、役立つ情報とサンプル コードが多数含まれています。