我有一个简单的界面:
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
?
更新:我的意思是接口......
答案 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())将推断它们被分配的类型。