简体   繁体   English

静态通用接口实现

[英]Static generic interface implementation

I have a simple interface: 我有一个简单的界面:

interface Predicate<T> {

boolean accepts(T in);

}

Now I would also like to provide sth of the form: 现在,我还要提供以下形式:

interface Predicate<T> {

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

boolean accepts(T in);

}

This is not legal in the form presented above. 上述形式不合法。 Is there a way to provide a generic implementation that would be typed ie in multiple context I could say Predicate.ALL , a bit like Collections.EMPTY_SET ? 有没有一种方法可以提供将要键入的通用实现,即在多个上下文中我可以说Predicate.ALL ,有点像Collections.EMPTY_SET

UPDATE: I meant interface... 更新:我的意思是接口...

You could use type inference just like Collections.emptySet() (note that Collections.EMPTY_SET doesn't use generics). 您可以像Collections.emptySet()一样使用类型推断(请注意, Collections.EMPTY_SET不使用泛型)。

From Collections : 来自Collections

public static final Set EMPTY_SET = new EmptySet();

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

You could mimic it like this: 您可以像这样模仿它:

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

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

you only need to replace <T> with something meaningful in the declaration of ALL . 您只需要用ALL声明中有意义的内容替换<T> Or remove altogether - note, Collections.EMPTY_SET is of type Set , not Set<T> . 或完全删除-注意, Collections.EMPTY_SET的类型为Set ,而不是Set<T>

To start with, your simple class is invalid because accepts doesn't have an implementation nor is it abstract. 首先,您的简单类无效,因为accepts没有实现,也不是抽象的。 Let's assume you meant to make it abstract, so that actual predicates are derived classes that override it. 假设您要使它抽象,以便实际谓词是覆盖它的派生类。 Then the ALL predicate is one that always returns true. 那么ALL谓词总是返回true。 But you can't make it a static field, because static fields cannot reference the type parameter. 但是您不能将其设置为静态字段,因为静态字段无法引用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; } };
  }
}

There are two ways to implement the ALL predicate: 有两种方法可以实现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);
}

You are declaring a concrete class field (a constant) here, so you must use a concrete replacement for the type variable T. As you are not interested in the type, you use the supertype of all objects: java.lang.Object. 您在此处声明一个具体的类字段(一个常量),因此必须对类型变量T使用具体的替换。由于您对类型不感兴趣,因此使用了所有对象的超类型:java.lang.Object。

This implementation would satisfy the compiler to not generate any warning and is a good starting point. 此实现将使编译器不产生任何警告,这是一个很好的起点。 However, you have some difficulties. 但是,您有一些困难。 Consider this code: 考虑以下代码:

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

Although test1 and test2 are both valid methods (and compile fine), the call to method test1 will not compile. 尽管test1和test2都是有效方法(并且可以正常编译),但对方法test1的调用将不会编译。 Simply put: A Predicate<Object> is not a Predicate<String>. 简而言之:Predicate <Object>不是Predicate <String>。

Conclusion: You must remember the PECS (producer extends, consumer super) when designing your methods that will take a Predicate as an argument. 结论:在设计将谓词作为参数的方法时,必须记住PECS(生产者扩展,消费者超级)。

The other option is to just not provide a type at all: 另一个选择是根本不提供类型:

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

With that implementation the above mentioned class PredicateTester compiles just fine. 通过该实现,上述类PredicateTester可以正常编译。 So, this is the way to go. 因此,这是要走的路。

In the form that you've written it you need it to be abstract as you're not providing the implementation of the accepts method. 按照您编写的形式,您需要它是抽象的,因为您没有提供accepts方法的实现。

abstract class Predicate<T> {

    abstract boolean accepts(T in);

}

If you then want to provide a multi use "accept any" predicate you can do it like this: 如果您随后想要提供多用途“ 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;}

This mimics the way that Collections.EMPTY_SET and Collections.emptySet() work. 这模仿了Collections.EMPTY_SET和Collections.emptySet()的工作方式。

Note that Collections.EMPTY_SET (and Predicate.ALL) are not type-safe but Collections.emptySet() (and Predicate.all()) will infer the type they are being assigned to. 请注意,Collections.EMPTY_SET(和Predicate.ALL)不是类型安全的,但是Collections.emptySet()(和Predicate.all())将推断要分配给它们的类型。

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

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