gpt4 book ai didi

java - Java 不允许在变量声明中使用泛型类型声明的任何原因?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:45:11 25 4
gpt4 key购买 nike

假设我们有这样一个类:

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没有绑定(bind)泛型类型,因此编译器不会“知道”foo.getValue() 的输出兼容 foo.setValue() 的输入.

因此,要解决此问题,您必须创建一个新方法来绑定(bind) 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 与各种通用类型一起被重置。换句话说,试图传递 Iterable<Foo<?>>导致编译错误。

This example演示问题:

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");
}

编译错误如下:

method resetFoos cannot be applied to given types;

required: Iterable<Foo<T>>

found: List<Foo<?>>

reason: no instance(s) of type variable(s) T exist so that argument type List<Foo<?>> conforms to formal parameter type Iterable<Foo<T>>where T is a type-variable:T extends Object declared in method <T>resetFoos(Iterable<Foo<T>>)

(通过 ideone.com 使用 sun-jdk-1.7.0_10)

最佳答案

基本上,类型变量目前在 Java 中只能有两个作用域:1) 类作用域,或 2) 方法作用域。您在问,为什么不允许另一个范围——本地代码块的范围(在本例中,是 for 循环的内部。

是的,在某些情况下这会很有帮助。将它添加到语言中并不难。然而,这些都是非常罕见的情况,并且更有可能使人们感到困惑而不是提供帮助。此外,正如您已经发现的那样,存在一个相对简单且有效的解决方法——将该本地 block 作用域移动到私有(private)辅助函数,然后该函数可以使用方法作用域类型变量:

public void resetFoos(Iterable<Foo<?>> foos) {
for (Foo<?> foo : foos) {
resetFoo(foo);
}
}

private <T> void resetFoo(Foo<T> foo) {
foo.setValue(foo.getValue());
}

是的,这可能会通过额外的方法调用降低代码的效率,但这是一个次要问题。

关于java - Java 不允许在变量声明中使用泛型类型声明的任何原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15887296/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com