繁体   English   中英

静态通用接口实现

[英]Static generic interface implementation

我有一个简单的界面:

interface Predicate<T> {

boolean accepts(T in);

}

现在,我还要提供以下形式:

interface Predicate<T> {

public static Predicate<T> ALL = new Predicate<T>(){ ... }

boolean accepts(T in);

}

上述形式不合法。 有没有一种方法可以提供将要键入的通用实现,即在多个上下文中我可以说Predicate.ALL ,有点像Collections.EMPTY_SET

更新:我的意思是接口...

您可以像Collections.emptySet()一样使用类型推断(请注意, Collections.EMPTY_SET不使用泛型)。

来自Collections

public static final Set EMPTY_SET = new EmptySet();

public static final <T> Set<T> emptySet() {
  return (Set<T>) EMPTY_SET;
}

您可以像这样模仿它:

public static Predicate ALL = new Predicate(){ ... }   

public static final <T> Predicate<T> all() {
  return (Predicate<T>) ALL;
}

您只需要用ALL声明中有意义的内容替换<T> 或完全删除-注意, Collections.EMPTY_SET的类型为Set ,而不是Set<T>

首先,您的简单类无效,因为accepts没有实现,也不是抽象的。 假设您要使它抽象,以便实际谓词是覆盖它的派生类。 那么ALL谓词总是返回true。 但是您不能将其设置为静态字段,因为静态字段无法引用type参数。

public abstract class Predicate<T> {
  public abstract boolean accepts(T in);

  public static <T> Predicate<T> all() {
    return new Predicate<T> { boolean accepts(T in) { return true; } };
  }
}

有两种方法可以实现ALL谓词:

public interface Predicate<T> {
    public static final Predicate<Object> ALL = new Predicate<Object> {
        @Override public boolean accepts(Object in) { return true; }
    }
    boolean accepts(T in);
}

您在此处声明一个具体的类字段(一个常量),因此必须对类型变量T使用具体的替换。由于您对类型不感兴趣,因此使用了所有对象的超类型:java.lang.Object。

此实现将使编译器不产生任何警告,这是一个很好的起点。 但是,您有一些困难。 考虑以下代码:

public class PredicateTester {
    public static void main(String[] args) {
        test1(Predicate.ALL, "some string"); // compiler error
        test2(Predicate.ALL, "some string");
    }
    public static void test1(Predicate<String> pred, String in) {
        System.out.println(pred.accepts(in) ? "pass" : "fail");
    }
    public static void test2(Predicate<? super String> pred, String in) {
        System.out.println(pred.accepts(in) ? "pass" : "fail");
    }
}

尽管test1和test2都是有效方法(并且可以正常编译),但对方法test1的调用将不会编译。 简而言之:Predicate <Object>不是Predicate <String>。

结论:在设计将谓词作为参数的方法时,必须记住PECS(生产者扩展,消费者超级)。

另一个选择是根本不提供类型:

public interface Predicate<T> {
    @SuppressWarnings("rawtypes")
    public static final Predicate ALL = new Predicate {
        @Override public boolean accepts(Object in) { return true; }
    }
    boolean accepts(T in);
}

通过该实现,上述类PredicateTester可以正常编译。 因此,这是要走的路。

按照您编写的形式,您需要它是抽象的,因为您没有提供accepts方法的实现。

abstract class Predicate<T> {

    abstract boolean accepts(T in);

}

如果您随后想要提供多用途“ accept any”谓词,则可以这样进行:

public static Predicate ALL = new Predicate(){
    @Override
    boolean accepts(Object in) {
        return true;
    }
};

@SuppressWarnings("unchecked")
static final <T> Predicate<T> all(){ return (Predicate<T>)ALL;}

这模仿了Collections.EMPTY_SET和Collections.emptySet()的工作方式。

请注意,Collections.EMPTY_SET(和Predicate.ALL)不是类型安全的,但是Collections.emptySet()(和Predicate.all())将推断要分配给它们的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM