Java 在番石榴中,为什么只是;";“在哪里使用?”;?超级T";可能吗?

Java 在番石榴中,为什么只是;";“在哪里使用?”;?超级T";可能吗?,java,generics,guava,bounded-wildcard,Java,Generics,Guava,Bounded Wildcard,为什么实用程序工厂方法经常使用特定的泛型参数(如T)而不是有界通配符参数(如?super T) 例如,签名是: 还有其他原因吗?是的,我们希望消费者拥有正确的有界通配符参数是绝对准确的,但我想到了另外两个原因: 一般来说,我们不会扩大泛型方法的类型,直到我们有一个明确的理由。这项政策已经取得了好几次成效 Java的类型推断并不总是能够自动找出更高级的泛型,因此保留较窄的泛型可以减少需要显式指定t的用户数量 在find()示例中,T始终可以明确推断 在forPredicate[1]()示例中,也

为什么实用程序工厂方法经常使用特定的泛型参数(如
T
)而不是有界通配符参数(如
?super T

例如,签名是:


还有其他原因吗?

是的,我们希望消费者拥有正确的有界通配符参数是绝对准确的,但我想到了另外两个原因:

  • 一般来说,我们不会扩大泛型方法的类型,直到我们有一个明确的理由。这项政策已经取得了好几次成效
  • Java的类型推断并不总是能够自动找出更高级的泛型,因此保留较窄的泛型可以减少需要显式指定
    t
    的用户数量
find()
示例中,
T
始终可以明确推断

forPredicate[1]()
示例中,也可以明确地推断T

forPredicate[2]()
示例中,不确定
T
应该是什么。如果将方法的结果分配给目标类型,则可根据目标类型确定
T
。否则就有点挠头了:

forPredicate(isPositive).apply(42);  // T is a subtype of Number, but which one?
在java5/6中,它不应该编译。(我在Java6上测试了它,它确实可以编译,但这可能是一个bug,因为Java6也可以编译
forPredicate(p).apply(“str”)

Java7有了一点改进,新规则恰好规定了
T=Number
。这是可行的,但感觉更像是为了它而进行的仲裁


理想情况下,我们不需要担心通配符。如果我的整数需要一个谓词,我应该声明一个
谓词
参数。
谓词
参数也可以接受的事实是另一回事。编译器的工作应该是将
谓词
转换为
谓词
——我们不需要大修现有的java泛型类型系统,只需要一个新的转换规则。还可以提供转换库

Predicate<Number>  pn = ...;
Predicate<Integer> pi = convert(pn);

Iterable<Integer> iter1 = ...;
Iterable<Number>  iter2 = convert(iter1);
但我们能做到

Predicate<Integer> pi = pn::test;  // ok
// it means        pi = (Integer i)->pn.test(i)
谓词pi=pn::test;//好啊
//它意味着pi=(整数i)->pn.test(i)

函数f=pn::test;//好啊

这相当于
f=forPredicate[2](pn)
。在Java8中,我们很少需要
forPredicate()
etc在函数类型之间进行转换。第一点,这不正是促使消费者选择两害相权取其轻吗?同样奇怪的是,当你说“我们”时,你的意思是说你是在这个基础上开发的,还是仅仅是在一般的软件社区上开发的。更具体地说,这个政策在实践中是如何得到回报的?目前,在我能想象的唯一重要的情况下,消费者会绕过转换为派生类型。当我说“我们”时,我的意思是我在开发Guava的Google Java核心库团队中。但消费者永远不需要强制转换:a
Predicate@LouisWasserman谢谢你的回答。我也很好奇,如果你有任何具体的例子,保持一个狭窄的类型得到回报。我关心的一个问题是(理论上)必须对一些没有很好地声明通配符的第三方代码使用
谓词
,在我看来,这可能需要一个包装器来“向上转换”参数,或者对
谓词
本身进行显式转换。但我想,当涉及多个通配符时,我可能会发现它变得非常混乱,因此我想尽可能避免这种麻烦可能是明智的:)forPredicate(isPositive)的
没有问题;在这种情况下,
T
是最具体的类型,
Number
Integer
继承自
Number
,因此
apply
调用没有问题。如果它是在你传入字符串时编译的,听起来有点像是用rawtypes之类的东西编译的。我的想法是:假设我的类中有一个私有的
谓词
,我想从一个方法返回它作为
函数
,我不应该向调用方公开它实际上是一个
谓词
。由于它接受所有的
Number
s,它也将接受所有的
Integer
s。现在要做到这一点,我必须用包装类或显式类来转换它。政治上正确的答案是方法返回类型应该是
function你是说
function否,它是一个接受
X
的函数,其中
X
是一个未知的
Integer
超类型。由于函数接受
X
,因此它接受
Integer
public static <T> T find(Iterable<T> iterable,
                         Predicate<? super T> predicate)
forPredicate(isPositive).apply(42);  // T is a subtype of Number, but which one?
Predicate<Number>  pn = ...;
Predicate<Integer> pi = convert(pn);

Iterable<Integer> iter1 = ...;
Iterable<Number>  iter2 = convert(iter1);
Predicate<Number>  pn = n -> n.intValue()>0;
Predicate<Integer> pi = pn;  // error!
Predicate<Integer> pi = pn::test;  // ok
// it means        pi = (Integer i)->pn.test(i)
Function<Integer, Boolean> f = pn::test;   // ok