【问题标题】:How to call a wildcarded method on a generic class?如何在泛型类上调用通配符方法?
【发布时间】:2014-11-15 05:53:12
【问题描述】:

我有一个泛型类,其中类型变量用于方法的参数。当我使用有界通配符从SetMapList 检索泛型类的实例时,如何调用此方法?

泛型类的超类:

//Verifier.java
import java.lang.annotation.Annotation;

public interface Verifier<A extends Annotation> {
    // A verifier needs the annotation to extract verification information.
    public boolean verifyValue(Object value, A annotation);
}

具体实现:

//MinMaxVerifyer.java
public class MinMaxVerifyer implements Verifier<MinMax> {
    @Override
    public boolean verifyValue(Object value, MinMax annotation) {
        if (!(value instanceof Number)) return false;

        long l = ((Number)value).longValue();
        long min = annotation.min();
        long max = annotation.max();

        return l >= min && l <= max;
    }
}

示例中使用的注解:

//MinMax.java
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
@Inherited
public @interface MinMax {
    long min() default Long.MIN_VALUE;
    long max() default Long.MAX_VALUE;
}

包含违规调用的类:

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

public class ParameterVerifier {
    private static final Map<String, Verifier<? extends Annotation>> verifyers
        = new HashMap<>();

    static {
        verifyers.put("MinMax", new MinMaxVerifyer());
        // verifyers.put(Range.class, new RangeVerifier());
        // verifyers.put(NotNull.class, new NotNullVerifier());
    }

    public void validate(Method method, Object value) {
        for (Annotation annotation : method.getAnnotations()) {
            String name = annotation.getClass().getSimpleName();
            Verifier<? extends Annotation> verifier = verifyers.get(name);

            if (verifier != null) {
                boolean valid = verifier.verifyValue(value, annotation);
                // ^ The method
                // verifyValue(Object, capture#5-of ? extends Annotation)
                // in the type Verifier<capture#5-of ? extends Annotation>
                // is not  applicable for the arguments (Object, Annotation)
            }
        }
    }
}

我正在尝试让这个工作,以便用户可以添加他们自己的注释/验证器对,并且验证器应该使用注释子类进行参数化。我不在乎是否必须在ParameterVerifier 中进行一些转换(而不是在公共API 的验证器中)。我知道如何通过一些额外的逻辑来使添加对类型安全,为了清楚起见,这里省略了。

相关:The method validate(capture#2-of ? extends Object) in the type Validator<capture#2-of ? extends Object> is not applicable for the arguments (String)Java generic/wildcard type mismatch 都建议限制为特定的 Verifier 子类型或从 Verifier 中删除类型变量。我正在寻找更优雅的解决方案。 (认为​​ MinMaxVerifyer.java 是不可变的,只适用于其他。)

【问题讨论】:

  • 我不确定是否可以不将泛型参数移动到方法中。例如参见:minmaxVerifier.varifyValue(null, somethingNotMinMax); 这似乎是不合理的。
  • "我知道如何通过一些额外的逻辑使添加对类型安全,为了清楚起见,这里省略了。"
  • 我看过那个评论,只是我怀疑它是可能的。你需要像 interface Verifier&lt;A super Annotation&gt; 这样的东西,它不是有效的 Java 语法。
  • 虽然在这种情况下我可以放宽MinMaxVerifyer的要求,如果添加方法泛型参数可以解决问题。
  • 当然,这就是为什么我提到将参数移动到方法(嗯,有错字),尽管它们与类泛型参数非常不同。可以尝试用不同的措辞来表达您到底想要实现什么?

标签: java generics


【解决方案1】:

我不知道为什么我以前没有找到这个。我想我会尝试各种泛型组合。这编译并完美地完成了这项工作。

  • 从检索到的元素中删除通配符(但不是泛型),然后进行强制转换并告诉编译器它是安全的。
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

public class ParameterVerifier {

    private static final Map<String, Verifier<? extends Annotation>> verifiers
        = new HashMap<>();

    static {
        verifiers.put(Range.class.getSimpleName(), new RangeVerifyer());
    }

    public void validate(Method method, Object value) {
        for (Annotation annotation : method.getAnnotations()) {
            String name = annotation.getClass().getSimpleName();
            @SuppressWarnings("unchecked")
            Verifier<Annotation> verifier =
                (Verifier<Annotation>)verifiers.get(name);
            if (verifier != null) {
                boolean valid = verifier.verify(value, annotation);
            }
        }
    }
}

【讨论】:

  • 抑制警告通常不是一个好主意,警告有一个目的:警告您代码有错误并且可能导致问题。代码现在可能会运行,但未来可能会发生不可预知的错误。
  • "警告您代码有问题并可能导致问题" 这不是真的。它只是告诉您编译器无法验证代码是否安全,因为它无法考虑用户想要的所有内容。在这些情况下,当用户可以证明代码是安全的时,@SuppressWarnings 是正确的做法。 (来自 Effective Java,第 24 项)(谷歌“有效 Java pdf”)
猜你喜欢
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多