2013-09-25 6 views
1

У меня есть этот интерфейс (упрощенный) JavaВыполнить конкретный метод параметризованную класса

public interface MyInterface<T> { 
    public String run(T arg); 
} 

и некоторые классы, которые реализуют этот интерфейс, т.е.

public final class SomeImplementation1 implements MyInterface<String> { 
    @Override 
    public String run(String arg) { 
     // do something with arg and return a string 
    } 
} 

и

public final class SomeImplementation2 implements MyInterface<CustomClass> { 
    @Override 
    public String run(CustomClass arg) { 
     // do something with arg and return a string 
    } 
} 

Теперь, У меня есть глобальный менеджер ресурсов для всех этих реализаций, который запускает все из них в списке для последнего Применение. То, что я хотел бы достичь, это что-то вроде этого, что, очевидно, дает мне ошибку

public final class MyInterfaceManager { 
    private List<MyInterface<?>> elements = new List<MyInterface<?>>(); 

    public MyInterfaceManager() { 
     elements.put(new SomeImplementation1()); 
     elements.put(new SomeImplementation2()); 
     // more implementations added 
    } 

    // this is what I would like to achieve 
    public <T> void run(T arg) { 
     for(MyInterface<?> element: elements) { 
      String res = element.run(arg); // ERROR 
     } 
    } 
} 

потому, что «аргумент не может быть преобразован, чтобы захватить № 1? С помощью вызова метода преобразования». Возможное решение может быть выполнить тест instanceof внутри цикла, и отбрасывать элемент его вещественного типа, наряду с аргументом, а также, как тот

public <T> void run(T arg) { 
     for(MyInterface<T> element: elements) { 
      if (element instanceof SomeImplementation2) { 
       String res = ((SomeImplementation2)element).run((CustomClass)arg ); 
      } else if // other tests here ... 
     } 
    } 

Но я не люблю его, это не элегантно, и это заставляет меня делать много instanceof и бросает. Итак, мне интересно, есть ли лучший способ достичь этого. Спасибо за вашу помощь :)

+1

Вы добавляете метод 'getClass' в' interface', а затем просто проверяете 'assignableFrom' для каждого экземпляра в' List', чтобы увидеть, можно ли безопасно передать переданный параметр в требуемый параметр, а затем вы ' Class.cast'. –

+0

@BoristheSpider спасибо за предложение, я попробую это завтра, потому что здесь немного поздно :) – Polentino

+0

@BoristheSpider Вы должны сделать ответ. –

ответ

1

Вы работаете на type erasure. Вам нужно добавить еще один метод к interface, который возвращает экземпляр Class, который относится к параметру типа <T>, это позволит вам выполнять проверки времени выполнения на этом Class.

Я бы сделать это таким образом:

public interface MyInterface<T> { 
    String run(T arg); 
    Class<T> type(); 
} 

Так interface возвращает его тип. Нотабене все interface членов public по умолчанию - нет необходимости в дополнительных public.

public final class SomeImplementation1 implements MyInterface<String> { 
    @Override 
    public String run(final String arg) { 
     return arg; 
    } 

    @Override 
    public Class<String> type() { 
     return String.class; 
    } 
} 

@SuppressWarnings({"unchecked"}) 
public static <T> String run(final T arg) { 
    for (final MyInterface<?> element : elements) { 
     if (element.type().isAssignableFrom(arg.getClass())) { 
      return ((MyInterface<T>) element).run(arg); 
     } 
    } 
    throw new IllegalArgumentException("No element found."); 
} 

Логика в том, что для каждого MyInterface вы проверить, является ли безопасно литьевой к тому, что MyInterface «s type() аргумент при условии. Если это так, вы можете отбросить целое число MyInterface до типа arg. Это не проверяется, поскольку компилятор не может проверить это как время компиляции, но по мере того, как вы вручную выполняете проверку, это предупреждение можно игнорировать.

public static void main(String[] args) throws Exception { 
    elements = new LinkedList<>(); 
    elements.add(new SomeImplementation1()); 

    System.out.println(run("test")); 
    System.out.println(run(1)); 
} 

Выход:

test 
Exception in thread "main" java.lang.IllegalArgumentException: No element found. 
    at com.XXX.App.run(App.java:33) 
    at com.XXX.App.main(App.java:55) 

Как и следовало ожидать.

+0

Спасибо, что дали явный ответ, проголосовали! :) – Polentino

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