3

Objective-C では、次のことができます。

id<HTTPRequestDelegate> delegate;

delegate(タイプ の変数) がプロトコルidに準拠している(またはJava 言語でインターフェースを実装している)と言えます。HTTPRequestDelegateHTTPRequestDelegate

HTTPRequestDelegateそうすれば、プロトコルによって定義されたメッセージを に送信するたびに、コンパイラはそれが応答delegateすることを理解します。delegate

Javaでこれを行うにはどうすればよいですか (つまり、ダック タイピング/ 動的タイピング)。

4

8 に答える 8

3

ダックタイピングはJavaには存在しません。クラスがインターフェースを実装する場合、このインターフェースが実装されていることを宣言する必要があります。インターフェイスのメソッドと同じシグネチャを持つメソッドを用意するだけでは不十分です。

ただし、インターフェースは型であり、この型の変数を宣言することができます。例えば:

List<String> myList;

myListタイプの変数を宣言します。List<String>ここListで、はインターフェイスです。

このリストインターフェイスを実装する任意のオブジェクトを使用して、この変数を初期化できます。

myList = new ArrayList<String>();

ただし、インターフェイスArrayListを実装することを宣言する必要がありListます(実装します)。

于 2011-07-05T20:04:23.027 に答える
2
//Static typing
HTTPRequestDelegate delegate;
于 2011-07-05T19:57:45.550 に答える
1
Interface a = new Implementation();
于 2011-07-05T19:54:57.063 に答える
0

Javaにはダックタイピングの概念がありません。インスタンスを既知のタイプにキャストする必要があります。

于 2011-07-05T20:03:50.473 に答える
0

すでに与えられた答えのほとんどは正しいです。オブジェクトがインターフェースを実装する場合、そのインターフェースの実装が必要な場所ならどこでもそのオブジェクトを使用できます。これは、Java の強力な型付けシステムを考えると、最も自然なアプローチです。

List/の例を維持するために、オブジェクトをArrayList作成し、それを必要な場所ならどこでも使用できます。または、他の実装されたインターフェイスに基づいて、、、、、または スーパークラスを考慮すると、 のインスタンスは、、またはとして使用できます。ArrayListListSerializableCloneableIterableCollectionRandomAccessArrayListAbstractListAbstractCollectionjava.lang.Object

リフレクションをダイナミック プロキシ オブジェクトと共に使用して、正しいメソッドを持つオブジェクトをアヒルのコスチュームにくさびで留めることができます。これにより、型チェックがランタイムに移行し、通常は、通常の型付けシステムに反対するよりも、それを使用するほうがはるかに優れた理由があります。

面白そうなので、Duck 以外のオブジェクトをプロキシ オブジェクトでラップする例を次に示します。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DuckDemo {
    public static Duck getDuckProxy(final Object duckLike) {
        final InvocationHandler invocationHandler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Class<?> actualClass = duckLike.getClass();
                String methodName = method.getName();
                Class[] parameterTypes = method.getParameterTypes();

                Method requested = actualClass.getDeclaredMethod (methodName, parameterTypes);

                return requested.invoke(duckLike, args);
            }
        };

        final ClassLoader originalObjectClassLoader = duckLike.getClass().getClassLoader();
        Duck woodenDuck = (Duck) Proxy.newProxyInstance(
                originalObjectClassLoader,
                new Class[] { Duck.class },
                invocationHandler
        );

        return woodenDuck;
    }

    private interface Duck {
        void quack();
    };

    public static void makeItQuack (Duck duck) {
        duck.quack();
    }

    public static void main (String args[]) {
        Object quacksLikeADuck = new Object() {
            void quack() {
                System.out.println ("Quack!");
            }
        };

        // Does not compile -- makeItQuack(DuckDemo.Duck) [...] cannot be applied to (java.lang.Object)
        // makeItQuack (quacksLikeADuck);

        // Runtime java.lang.ClassCastException: [...] cannot be cast to GenericProxyFactory$Duck
        // makeItQuack ((Duck)quacksLikeADuck);

        Duck d = getDuckProxy(quacksLikeADuck);

        makeItQuack (d);
    }
}

価値のあることとして、IBM developerWorks には、動的プロキシーのトピックに関する優れた記事もあります。

于 2011-07-06T05:19:28.517 に答える
0

私はデリゲートがあなたが望むインターフェースを明示的に実装していないと仮定しています。

インターフェイスを実装し、必要な実装クラスを拡張する新しいクラスを作成できます (または、実装クラスを持ち、インターフェイスで適切なメソッドを明示的に呼び出します)。

これがあなたの望むものではない場合、あなたは健全な量の反省をしているかもしれません. java.lang.reflect.Proxy と InvocationHandler を見てください。

コンポジションを使用してインターフェイスのメソッドを明示的に実装することを避けるための省略形を探している場合、Java はこれに対する構文サポートを実際には提供していません。明確にする必要があります。

リフレクションを多用したい場合 (余分な入力はお勧めしません)、Mockito をご覧ください。

于 2011-07-05T20:12:28.683 に答える
0

Objective-C では、型は 2 つの部分で構成されます。1) クラス ポインタ型 (例: NSObject *NSString *など)。これidは、任意のオブジェクト ポインターを受け入れることができ、メソッドの呼び出しに対する静的型コンパイラの警告を無効にする特別な型です。2) オプションで、オブジェクトが準拠する 1 つ以上のプロトコル (Java のインターフェースのようなもの) (例: <NSCopying, NSCoding>)

Java では、参照型はクラス名またはインターフェース名です。(選択できるのは 1 つだけです。) クラスとインターフェイスの間にはそれほど大きな隔たりはありません。

あなたの場合、オブジェクト ポインターの型はidであり、これは情報を表現せず、1 つのインターフェイスを指定しHTTPRequestDelegateました。これは、Java で次のように同等に表現できます。

HTTPRequestDelegate delegate;

複数のプロトコルを指定した場合、または実際のクラス ポインター型と 1 つ以上のプロトコルを指定した場合、型は「交差型」、つまり指定した複数の型の共通部分になります。その場合、Java で交差タイプを表現する簡単な方法がないため、より困難になります。(交差タイプはジェネリック タイプ境界で指定できますが、たとえばclass Foo<T extends Collection & Comparable & CharSequence>)

それ以外で、Objective-C と Java の他の唯一の違いは、Objective-C では、オブジェクト ポインターで任意のメッセージを送信 (つまり、任意のメソッドを呼び出す) できることです。サポートされていることを示しません (実際のクラス ポインター型を使用すると、コンパイラーは警告を出しますが、それを使用idしても警告は出ません)。これはあなたが話している動的型付けだと思います。一方、Java では、コンパイル時に static 型でサポートされていることがわかっているメソッドのみを呼び出すことができます。

しかし、 のような型を使用している場合は、とにかくid<HTTPRequestDelegate>によって提供されるメソッドのみを使用するつもりである可能性が高いHTTPRequestDelegateため、動的型付け機能を使用していません。したがって、Java では HTTPRequestDelegate だけで十分です。

于 2011-07-06T11:55:49.697 に答える
-1

ここで展開する用語はたくさんあると思います。Java では、生のポインターは使用できず、型を持つ参照のみを使用できます。

とにかく、実装していることがわかっているインスタンスへの参照があるとしますHTTPRequestDelegate。次のようにキャストできます。

HTTPRequestDelegate delegate = (HTTPRequestDelegate) ref;

括弧内のビットはキャストです。delegateでメソッドが定義されている限り、(Java でメッセージを渡す) のメソッドを心ゆくまで呼び出すことができるようになりましたHTTPRequestDelegate

Java プログラマーがダック タイピング タイプを行うもう 1 つの方法はリフェクションですが、インターフェイスを知っている場合は、ケーシングを使用することをお勧めします。

于 2011-07-05T19:58:40.113 に答える