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核心库团队中。但消费者永远不需要强制转换:aPredicate@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