-1
public class Test<T extends Test.Mapper<?>> {
    SomeFactory<T> factory;

    public Test(SomeFactory<T> factory) {
        this.factory = factory;
    }

    public <V> V handle(T<V> request) { // fails how to get Class<V> of request.getCls() of a mapper or its subtype?
        HttpUriRequest httpUriRequest = factory.get(request); // does not work
        // decode response and return it as an object represented by request.getCls
        return null;
    }

    public interface Mapper<T> {
        Class<T> getCls();
    }

    public interface SomeMapper<T> extends Mapper<T> {
        void doSomeAdditional();
    }

    public interface SomeFactory<T extends Test.Mapper<?>> {
        HttpUriRequest get(T mapper);
    }
}

handle メソッドは、http 要求を実行し、応答本文を Mapper の getCls() メソッドによって表されるオブジェクトにデコードする汎用メソッドです。SomeFactory 実装は、そのタイプにのみ固有のいくつかのメソッドにアクセスする必要があるため、このクラスで Mapper のさまざまなサブタイプを処理できるようにしたいと考えています。

これに沿った何か

SomeFactory<SomeMapper<?>> somefactory = // factory implementation
Test<SomeMapper<?>> test = new Test<SomeMapper<?>>(someFactory);
test.handle(implementation of SomeMapper<Integer>); // should return an instance of Integer

明確化: 基本的に、Test のインスタンス化は、Test の実際のタイプ (SomeMapper または Mapper) に対応する handle() タイプのみにする必要があります。handle メソッドは、この実際のタイプのリクエストを受け取ることができます。

IEだった場合Test<SomeMapper<?>> test 、次のようなリクエストがあります

ASomeMapper implements SomeMapper<Double> {}
BSomeMapper implements SomeMapper<Integer> {}

test.handle(new ASomeMapper()); // this should return Double
test.handle(new BSomeMapper()); // this shold return Integer

多分私は再設計する必要がありますか?

4

1 に答える 1

1

あなたがやろうとしていることに対してそれが受け入れられるかどうかはわかりませんが、これを行うことができます:

public class Test<V, T extends Test.Mapper<V>> {
    SomeFactory<T> factory;

    public Test(SomeFactory<T> factory) {
        this.factory = factory;
    }

    public V handle(T request) {
        return null;
    }

    public static interface Mapper<A> {
        Class<A> getCls();
    }

    public interface SomeMapper<T> extends Mapper<T> {
        void doSomeAdditional();
    }

    public interface SomeFactory<T extends Test.Mapper<?>> {
        HttpUriRequest get(T mapper);
    }
}

または、これを行うこともできますが、2 つ以上のパラメーターを使用してジェネリック メソッドを呼び出すときは、常にパラメーターを定義する必要があります。

    public <V, Z extends T> V handle(Z request) {
        return null;
    }

例でやろうとしていたように、パラメーターをさらにパラメーター化することはできません。

もう1つの解決策は、1ステップ戻ってこれを行うことです:

    public <V> V handle(Test.Mapper<V> request) {
        return null;
    }

したがって、適切な Mapper タイプであることは保証しますが、その実装は保証しません。

あなたがそれをどのように使おうとしているかについては、そのようにはまったく機能しません。定義しようとしているのは、(クラスだけでなく) ジェネリック メソッドです。したがって、基本的に別のパラメーターをメソッドに提供する必要があり、これは代入によって定義されます。

この ASomeMapper をどのように実装しても、ここの行はコンパイルされません。

test.handle(new ASomeMapper());

次のことを行うように求められます。

Double value = test.handle(new ASomeMapper());

この方法でのみ、実際に Double を返したいことがわかります。ASomeMapper が Double パラメータと一致しない場合、コンパイラは文句を言いますが、一致する場合はコンパイルします。あるいは、次のように定義すると:

Object value = test.handle(new ASomeMapper());

それでも警告が表示されますが、これはエラーとして扱われるべきです。それはあなたが何を返したいのか本当にわからず、型チェックなしで ASomeMapper でコード化されたものを返すからです。それを Object に割り当てたいが、それでも型チェックが必要な場合は、メソッド呼び出しを明示的にパラメーター化する必要があります。

new Test<SomeMapper<?>>(null).<Double>handle(null);
于 2013-02-25T21:55:33.343 に答える