2016-03-18 3 views
4

Javaの場合は、final class Carを提供するライブラリを使用し、インターフェイスを実装したい場合があります。Truckクラス内でVehicleとして扱います。しかし、Carは最終的なもので、インターフェースを実装していません。クラスが実装すると主張していない互換クラスに最終クラスをキャスト

他の車両のように他の人の最終Carクラスを私のVehicleインターフェイスにキャストするにはどうすればいいですか? Vehicleのすべてのインスタンスメソッドは、インスタンスメソッド名、引数型、および戻り型に関して、Carの同様のメソッドと100%互換性があります。これは、ダックタイピングの観点からは同等です。

私はMyCar extends Vehicleラッパークラスを作成して、各メソッド呼び出しを内部のCarオブジェクトに委譲することができます。それはJava Wayです。しかし、実際にあるクラスを無関係な(ただし100%互換性のある)インターフェイスにキャストするテクニックがあるかどうかは不思議です。答えが悪ければOKです。

+5

いいえ、ラッパーソリューション(組成)は唯一の方法です。 –

+0

JDKプロキシインターフェイスを使用できます。 – chrylis

+0

@ PaulBoddington JVMの制限、またはJava言語の制限ですか?つまり、クラスローダーやバイトコードをハッキングすると、この制限を回避できますか?私はClojureとGroovyがこのようなことをすることができると思います。 – GlenPeterson

答えて

-1

あなたが言ったように私は個人的には、それのためのラッパークラスを作成します。
Carのインタフェースへの参照は役に立ちますか?

public abstract class MyCar implements Vehicle { 

    private Car car; 

    (...) 
} 

はこれを行うには非常に多くの方法がありません、と私は私の方法は、あなたが望むものであるも、それは完全に有効かどうかわかりません。

import java.lang.reflect.Proxy; 

public class DuckTyping { 

    static final class Car{ 
     public void honk(){ 
      System.out.println("honk"); 
     } 
    } 

    interface Vehicle{ 
     void honk(); 
    } 

    public static void main(String[] a){ 
     Car c = new Car(); 
     Vehicle v = (Vehicle) Proxy.newProxyInstance(Vehicle.class.getClassLoader(), new Class[]{Vehicle.class}, (proxy, method, args) -> 
      Car.class.getMethod(method.getName(), method.getParameterTypes()).invoke(c, args) 
     ); 

     v.honk(); 
    } 
} 

ジェネリック方法:

+1

申し訳ありませんが、それは本当に "答え"の価値がありません。あなたが説明する必要がある場合は、なぜこれを行う唯一の方法であるのか説明してください。 – GhostCat

+1

また、 'implements Vehicle'が必要です。これはインターフェースです。 –

5

は、プロキシでそれを行う

static <T> T proxyCast(Object targetObject, Class<T> targetClass) { 
     return (T) Proxy.newProxyInstance(targetClass.getClassLoader(), new Class[]{targetClass}, (proxy, method, args) -> 
      targetObject.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(targetObject, args) 
     ); 
    } 
2

これを行う最も簡単な方法は、JDKプロキシである:

public class DuckTyper { 

    public static <T> T quack(Object target, Class<T> duck) { 

     return (T) Proxy.newProxyInstance(duck.getClassLoader(), new Class[] { duck }, new DuckCostume(target)); 

    } 

    private static class DuckCostume implements InvocationHandler { 

     private final Object target; 

     public DuckCostume(Object target) { 

      this.target = target; 

     } 

     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 

      Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes()); 
      return targetMethod.invoke(target, args); 
     } 

    } 

} 

(束があります。未処理の例外があり、リフレクションのどれもキャッシュされていないので、それを行うまでは遅くなりますが、これで出発点が得られます)

この後、あなたはこのようにあなたの車をアヒル-入力することができます。

Vehicle carVehicle = DuckTyper.quack(car, Vehicle.class); 
3
  1. クラスの最終修飾子は、その状態の変更を許可しないように作られた、それはをですので、方法はありませんクラスを変更します。あなたが親クラスから拡張したり、インターフェイスに実装する場合はキャストがだけあなたのためを働くだろう

  2. は、他に方法はありません(ただし、クラスは最終的なものでない可能性があるため)この場合

  3. 3つのオプションがあります: 1.ラッパー(あなたが言及します)。 2.リフレクション(実行時にクラスとそのメソッドに関する有用な情報を知ることができます)。 3.独自のクラスを作成します。

関連する問題