2013-09-25 2 views
1

을 실행 내가 가진이 (간체) 자바 인터페이스특정 매개 변수화 클래스 메소드

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를 캡처 변환 할 수 없습니다? 메소드 호출 변환에 의해". 그렇지 않아, 가능한 솔루션은

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 테스트를 수행하고 실제 유형 요소를 투영 할 수 있습니다하지만 난 그것을 좋아하지 않아 우아한 전혀, 그리고 나를 instanceof과 캐스트의 제비를 할 것을 강요합니다. 그래서 이것을 달성하는 더 좋은 방법이 있는지 궁금합니다. 도움을 주셔서 감사합니다.

+1

'getClass' 타입의 메소드를'interface'에 추가 한 다음,'List'의 각 인스턴스에 대해'assignableFrom'을 체크하여 전달 된 파라미터가 필요한 파라미터로 안전하게 캐스팅 될 수 있는지 확인한 후, 그것을 캐스팅하는 Class.cast'. –

+0

@BoristheSpider이 제안에 감사드립니다. 내일이면 시도해 보겠습니다. – Polentino

+0

@BoristheSpider 답변을 작성해야합니다. –

답변

1

type erasure로 실행됩니다. 유형 매개 변수 <T>과 관련된 Class 인스턴스를 반환하는 interface에 다른 메소드를 추가해야합니다. 그러면 Class에 대한 런타임 검사를 수행 할 수 있습니다.

따라서 나는이 작업을 수행 할 것입니다 :

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

는 그래서 interface이 유형을 반환합니다. N.B. 모두 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에 대해 사용자가 제공 한 인수가 MyInterfacetype() 안전하게 스트 여부를 확인한다는 것입니다. 그러면 전체 MyInterfacearg 유형으로 전송할 수 있습니다. 컴파일러가 이것을 컴파일 타임으로 확인할 수 없으므로이 옵션의 선택이 해제되어 있지만 수동으로 확인을 수행하면이 경고를 무시할 수 있습니다.

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

관련 문제