假设我们有一个这样的类:
public class xx {
public interface Foo<T> {
T getValue();
void setValue(T value);
}
public void resetFoos(Iterable<Foo<?>> foos) {
for (Foo<?> foo : foos)
foo.setValue(foo.getValue());
}
}
即使从直觉上看它似乎“应该”,它也将无法编译:
xx.java:10: setValue(capture#496 of ?) in xx.Foo<capture#496 of ?> cannot be applied to (java.lang.Object)
foo.setValue(foo.getValue());
原因是它foo
没有绑定的泛型类型,因此编译器不“知道” 的输出foo.getValue()
与 . 的输入兼容foo.setValue()
。
因此,要解决此问题,您必须创建一个新方法,仅用于在for()
循环中绑定泛型类型参数:
public class xx {
public interface Foo<T> {
T getValue();
void setValue(T value);
}
public void resetFoos(Iterable<Foo<?>> foos) {
for (Foo<?> foo : foos)
this.resetFoo(foo);
}
// stupid extra method here just to bind <T>
private <T> void resetFoo(Foo<T> foo) {
foo.setValue(foo.getValue());
}
}
这一直困扰着我。另外,似乎可以有一个简单的解决方案。
我的问题:有什么“好的”理由不应该扩展 java 语言以允许对变量声明进行泛型类型声明?例如:
public class xx {
public interface Foo<T> {
T getValue();
void setValue(T value);
}
public void resetFoos(Iterable<Foo<?>> foos) {
for (Foo<?> foo : foos) {
final <T> Foo<T> typedFoo = foo;
foo.setValue(foo.getValue());
}
}
}
for()
或者,在这种循环的情况下更简洁:
public class xx {
public interface Foo<T> {
T getValue();
void setValue(T value);
}
public void resetFoos(Iterable<Foo<?>> foos) {
for (<T> Foo<?> foo : foos)
foo.setValue(foo.getValue());
}
}
我想知道是否某些编译器向导可以解释为什么这太难了,或者可以(并且应该)完成。
编辑:
针对这个建议的解决方案:
public <T> void resetFoos(Iterable<Foo<T>> foos) {
for (Foo<T> foo : foos) {
foo.setValue(foo.getValue());
}
}
此方法签名不允许将Foo
具有各种泛型类型的 s 一起重置。换句话说,尝试传入 anIterable<Foo<?>>
会导致编译错误。
这个例子演示了这个问题:
public static class FooImpl<T> implements Foo<T> {
private T value;
public FooImpl(T value) { this.value = value; }
@Override public T getValue() { return value; }
@Override public void setValue(T value) { this.value = value; }
}
public static <T> void resetFoos(Iterable<Foo<T>> foos) {
for (Foo<T> foo : foos) {
foo.setValue(foo.getValue());
}
}
public static void main(String[] args) {
final Foo<Object> objFoo = new FooImpl<>(new Object());
final Foo<Integer> numFoo = new FooImpl<>(new Integer(42));
final Foo<String> strFoo = new FooImpl<>("asdf");
List<Foo<?>> foos = new ArrayList<>(3);
foos.add(objFoo);
foos.add(numFoo);
foos.add(strFoo);
resetFoos(foos); // compile error
System.out.println("done");
}
编译错误显示:
方法
resetFoos
不能应用于给定类型;必需的:
Iterable<Foo<T>>
成立:
List<Foo<?>>
原因:不
T
存在类型变量的实例,因此参数类型List<Foo<?>>
符合形参类型Iterable<Foo<T>>
whereT
is a type-variable:T extends Object
在方法中声明<T>resetFoos(Iterable<Foo<T>>)
(通过 ideone.com 使用 sun-jdk-1.7.0_10)