2013-04-22 32 views
3

我有一个Predicate<Object>,需要一个等效的Predicate<Animal>逆转换番石榴预测

Predicate<Animal> provideIsSentientPredicate() { 
    // Won't compile -- cannot convert from Predicate<Object> to Predicate<Animal> 
    return Predicates.instanceOf(Human.class); 
} 

谓词是逆变,所以转换Predicate<Object>Predicate<Animal>是安全的。是否有干净可读的方式将Predicate<Object>转换为Predicate<Animal>(例如不禁止警告)?

我不想改变我的方法的类型签名来返回一个Predicate<? super Animal>Predicate<Object>除非有人说服我,是做正确的事。

+0

可选的相关问题:http://stackoverflow.com/questions/7848789/how-to-use-guava-optional-as-naturally-covariant-object – 2013-04-22 17:20:30

+0

“Predicates.instanceOf”的类型绝对是为了推你要么返回一个'谓词<?超级动物>',或者返回'Predicate '并且改变调用者期望'谓词<?超级动物>'。 – 2013-04-22 17:31:27

+0

@Louis哇!真?那完全不是我的期望!我一直认为用一个通配符类型来处理客户端是很粗鲁的,所以我从来没有写过一个带有通配符返回类型的方法。通配符返回类型是否被认为是良好的实践?我无法回想起Guava源代码树中返回通配符类型的任何方法 - 有没有一种方法? – 2013-04-22 17:57:08

回答

4
Predicate<Animal> provideIsSentientPredicate() 
{ 
    return cast(Predicates.instanceOf(Human.class)); 
} 

static <A, B extends A> Predicate<B> cast(Predicate<A> pa) 
{ 
    @SuppressWarnings("unchecked") 
    Predicate<B> pb = (Predicate)(pa); 
    return pb; 

    // we know it works correctly in practice. 
    // or if you are a theorist, create a wrapper predicate 
    // 
    //  Predicate<B> 
    //   boolean apply(B b) 
    //    return pa.apply(b); 
} 

顺便说一句,有没有理由番石榴不应申报方法

static <T> Predicate<T> instanceOf(Class<?> clazz) 

与其他兄弟姐妹方法一致。

+1

是的,我不明白为什么它不是静态的谓词 instanceOf(类 clazz)',但番石榴团队通常有这样的事情很好(如果微妙)的原因。 Guava在其他静态工厂方法('Ordering.allEqual()','Ordering.arbitrary()','Ordering.usingToString()')中避免了泛型,而@Louis注释似乎表明'Predicates.instanceOf()'' s返回类型是故意的。尽管如此,仍然不知道为什么。 – 2013-04-22 19:54:57

+2

在回复我之前的评论时,我猜想最可能的原因是“谓词 instanceOf(类 clazz)”的方法签名不是“static”谓词 instanceOf(类 clazz)'是第二个签名更多复杂的,难以测试的,难以阅读的,不太适应的,并且在足够的情况下不能在第一签名方面具有优势来进行切换。但是,如果有比这更深的原因,我真的很好奇听到它。 – 2013-04-22 20:07:11