2017-01-11 9 views
1

Javaリフレクションで取得したクラスをサブクラス化することは可能ですか?私はすでにロードされているクラスのメソッドの実装を変更しようとしています。私は定期的な反射方法でそれを行う方法がないことを知っています。取得したクラスをJavaリフレクションでサブクラス化することは可能ですか?

final Class cls = classLoader.loadClass(className); 
Object newRemoteInstance = new cls() { 
    @Override 
    public void saySth() { 
     System.out.println("changed"); 
    } 
} 

代わりの

cls.newInstance(); 

とまったく同じ実装を取得した後に、既にロードされたクラスのフィールドをコピーする:それはのような、検索されたクラスをサブクラス化することにより可能である場合しかし、私は思っていました新しく作成されたインスタンスと、すでにロードされているインスタンスの代わりにこの新しいインスタンスを使用します。変更するクラスは使用できないので、リフレクションを使用する必要があります。

ありがとうございます。

答えて

1

これを反映させるために必要なものが何であるかは、あなたの質問ではっきりしていません。リフレクションを使用してインスタンスを作成し、それをプロキシまたはデコレータにラップするだけで、その動作を向上または変更できるためです。 MyDecoratorはもちろんのMyClassと同じパブリックインターフェイスを実装し

class MyFactory { 
    MyClass create() { 
     return MyDecorator(cls.newInstance()); 
    } 
} 

しかし、実際にリフレクションでこれを行う必要がある場合は、あなたが気にするものに応じて、動作する可能性があるいくつかの選択肢がわかります。 Javaのプロキシに

を使用して

問題のあなたの方法は、インターフェースから来た場合は、その動作を変更するためにJava Proxyを使用することができます。

OrderService subject = new DefaultOrderService(); 
OrderService orderService = (OrderService) Proxy.newProxyInstance(
     this.getClass().getClassLoader(), 
      new Class<?>[]{OrderService.class}, 
      (proxy, method, args) -> { 
       try { 
        System.out.println("Before method"); 
        return method.invoke(subject, args); 
       } 
       finally { 
        System.out.println("After method"); 
       } 
      } 
     ); 
System.out.println(orderService.getClass()); 
orderService.getOrder(10); 

多少のクラス名のためにこのような利回り上記出力:プロキシのクラスとしてcom.sun.proxy.$Proxy24.class。あなたがあなたの代わりにcglibのようなライブラリを使用することができ、通常のクラスではなくインタフェースを使用するように強制されている場合は、

しかしJavaのCGLIBを使用し

プロキシは元のクラス(つまりDefaultOrderService)から継承しています。これには利点があります。プロキシを作成できるようにするために、問題のクラスがインターフェイスを実装している必要はありません。これはあなたの質問にあるようです。

DefaultOrderService subject = new DefaultOrderService(); 
Enhancer enhancer = new Enhancer(); 
enhancer.setSuperclass(DefaultOrderService.class); 
enhancer.setCallback((InvocationHandler) (obj, method, args) -> { 
    try { 
     System.out.println("Before method"); 
     return method.invoke(subject, args); 
    } 
    finally { 
     System.out.println("After method"); 
    } 
}); 

OrderService orderService = (OrderService) enhancer.create(); 
System.out.println(orderService.getClass()); 
orderService.getOrder(10); 

上記の出力結果は、拡張オブジェクトのクラスとしてDefaultOrderService$$EnhancerByCGLIB$$9017bdba.classのようになります。

しかし、どちらの例も、別のインタフェースと同じインタフェースを持つ新しいクラスを定義することであり、元の親クラスまたはインタフェースを変更しません。

+0

あなたの最後の例は、まさに私があなたに感謝する必要があります! AndroidはDalvikのバイトコードを実行するのに対し、CGlibはJavaのバイトコードを生成するため、残念ながらAndroid(私のプロジェクトのベース)は動作しません。同等の機能を提供するAndroidの代替手段を知っていますか?編集:私は実際に見つけたhttp:// bytebuddy。net /の最新バージョンでAndroidをサポートしていると主張しているので、 – Phoebus

関連する問題