3

次のインターフェースと実装があるとします。

interface Matcher<T>{
     boolean matches(T arg);
}

class NumberMatcher<T extends Number> implements Matcher<T>{
    @Override
    public boolean matches(T arg){...}
}

class StringMatcher extends Matcher<String>{
   @Override 
   public boolean matches(String arg){ ...}
}

class CustomMatcher extends NumberMatcher<Integer> {
    public boolean matches(String arg){...}

    @Override
    public boolean matches(Integer arg){...}
}

必要なのは、特定の Matcher 実装の matches(T) メソッドのパラメーターの型です。

NumberMatcher numberMatcher = new NumberMatcher<Long>();
StringMatcher stringMatcher = new StringMatcher();
CustomMatcher customMatcher = new CustomMatcher();
Matcher<Date> dateMatcher = new Matcher<Date>(){...};

getArgumentType(numberMatcher) // should return Number.class
getArgumentType(stringMatcher) // should return String.class
getArgumentType(customMatcher) // should return Integer.class
getArgumentType(dateMatcher ) // should return Object.class

CustomMatcher の場合を除いて機能する実装を次に示します。これは、オーバーライドされた matches(..) メソッドの検出に失敗し、String.class代わりに を返すためですInteger.class

Class<?> getArgumentType(Matcher<?> matcher) {
    Method[] methods = matcher.getClass().getMethods();
    for (Method method : methods) {
        if (isMatchesMethod(method)) {
            return method.getParameterTypes()[0];
        }

    }
    throw new NoSuchMethodError("Method 'matches(T)' not found!");
}

private boolean isMatchesMethod(Method method) {
    if (!isPublic(method.getModifiers()))
        return false;

    if (method.getParameterCount() != 1)
        return false;

    return method.getName().equals("matches");
}

編集:

次のように引数の型を指定する必要のないソリューションを探しています。

interface Matcher<T>{
     boolean matches(T arg);
     Class<T> argumentType();
}
4

1 に答える 1

0

実装を編集できる限り、マーカー アノテーションを使用できます。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ThisIsTheOne {

}

public class CustomMatcher extends NumberMatcher<Integer> {

    @Override
    @ThisIsTheOne
    public boolean matches(Integer arg){ return true; }

    public boolean matches(String arg){  return true; }
}

private static boolean isMatchesMethod(Method method) {
    if (method.getAnnotation(ThisIsTheOne.class) != null) {
        return true;
    }
    // do the same as before, so it works on non-annotated methods too
}

これは に対して返さInteger.classCustomMatcherます。

Method-s はどこから来たのかわからないため、実行時にこの情報を取得する方法はないと思います。複数のインターフェイスが同じメソッド シグネチャを定義できるため、これはおそらく意図的なものです。

于 2016-06-28T10:47:09.043 に答える