2013-02-25 2 views
-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); 
    } 
} 

Способ ручка представляет собой метод общего назначения, который выполняет запрос HTTP, а затем декодирует тело ответа в объект, который представлен getCls Преобразователь по методу(). Я хотел бы этот класс для обработки различных подтипов Mapper, так как SomeFactory реализации требуется для доступа некоторые методы только частности, к этому типуРодовой Подтип

Что-то вдоль линий этого

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

Разъяснение: В основном конкретизации теста должны обрабатывать только типы(), соответствующие фактическому типу теста (SomeMapper или Mapper). Затем метод handle может принимать любые запросы этого фактического типа.

I.E. Если бы это было 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 

Может быть, я должен переделать?

ответ

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 шаг и сделать это:

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, без каких-либо проверок типов. Если вы хотите назначить его объекту и все еще хотите проверить тип, вам придется параметризовать вызов метода явно.

new Test<SomeMapper<?>>(null).<Double>handle(null); 
+0

Да, это именно то, что я пытаюсь сделать, так что это невозможно без кастинга? Поскольку фактический тип ASomeMapper известен во время компиляции, не может ли он это сделать? Это подтип SomeMapper. – xxtommoxx

+0

Я обновил свой ответ с большим количеством объяснений, но вы как бы смешиваете 2 вещи. Общий метод с общим классом. Ваш код может поддерживать оба, но их сложно смешивать. – ATrubka

+0

Пожалуйста, посмотрите на конец моего ответа. Это объясняет, почему вы не сможете использовать его так, как хотите. – ATrubka

Смежные вопросы