[英]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.