roe*_*erj 8 java generics foreach
如何迭代通配符通用?基本上我想内联以下方法:
private <T extends Fact> void iterateFacts(FactManager<T> factManager) {
for (T fact : factManager) {
factManager.doSomething(fact);
}
}
Run Code Online (Sandbox Code Playgroud)
如果此代码在如图所示的单独方法中,则它起作用,因为泛型方法上下文允许定义通配符类型(此处T)可以迭代.如果尝试内联此方法,则方法上下文消失,并且不再迭代通配符类型.即使在Eclipse中自动执行此操作也会失败并显示以下(无法编译)代码:
...
for (FactManager<?> factManager : factManagers) {
...
for ( fact : factManager) {
factManager.doSomething(fact);
}
...
}
...
Run Code Online (Sandbox Code Playgroud)
我的问题很简单:有没有办法放一些可以迭代的通配符类型,或者这是泛型的限制(意味着不可能这样做)?
在这种情况下,解决方法是创建一个辅助方法.
JLS有这个例子http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.10
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list) { ... }
Run Code Online (Sandbox Code Playgroud)
问题是,我们有一个List<?>对象.我们知道它必须是List<X>一些X,我们想用代码编写代码X.内部编译器确实将通配符转换为类型变量X,但Java语言不能为程序员提供访问它的直接方法.但是如果有方法接受List<T>,我们可以将对象传递给方法.编译器推断出这个T=X并且通话很好.
如果没有类型擦除,X可以在运行时知道,那么Java肯定会给我们一种访问方式X.但是截至今天,由于X在运行时不可用,因此没有多大意义.可以提供纯粹的合成方式,这不太可能比辅助方法更简单.
类型参数只能定义在
您需要本地块的类型参数,这是不可能的。
是的,我有时也会错过这样的事情。
但这里的方法非内联并不是真正的问题 - 如果它出现内联会有所帮助的性能瓶颈,Hotspot 将再次内联它(不关心类型)。
此外,拥有一个单独的方法可以给它一个描述性的名称。
只是一个想法,如果你经常需要这个:
interface DoWithFM {
void <T> run(FactManager<T> t);
}
...
for (FactManager<?> factManager : factManagers) {
...
new DoWithFM() { public <T> run(FactManager<T> factManager) {
for (T fact : factManager) {
factManager.doSomething(fact);
}
}.run(factManager);
...
}
...
Run Code Online (Sandbox Code Playgroud)