静态通用接口实现

时间:2013-12-13 10:49:06

标签: java generics interface

我有一个简单的界面:

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

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

5 个答案:

答案 0 :(得分:3)

您可以像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;
}

答案 1 :(得分:1)

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

答案 2 :(得分:1)

首先,您的简单类无效,因为accepts没有实现,也不是抽象的。假设您打算将其设为抽象,以便实际谓词是覆盖它的派生类。然后ALL谓词总是返回true。但是你不能把它变成静态字段,因为静态字段不能引用类型参数。

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; } };
  }
}

答案 3 :(得分:1)

有两种方法可以实现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。对象

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

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的调用将不会编译。简单地说:A Predicate&lt; Object&gt;不是Predicate&lt; String&gt;。

结论:在设计将谓词作为参数的方法时,您必须记住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编译得很好。所以,这是要走的路。

答案 4 :(得分:0)

在你编写它的形式中,你需要它是抽象的,因为你没有提供accept方法的实现。

abstract class Predicate<T> {

    abstract boolean accepts(T in);

}

如果您想提供多用途的“接受任何”谓词,您可以这样做:

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())将推断它们被分配的类型。