2

我有一个具有以下定义的类:

public abstract class A<T> implements Iterator<B> {}

以下对 next() 的调用将返回 Object 而不是 B:

A a = new SomethingThatExtendsA();
B b = a.next();

我已经搜索了很长时间,但无法弄清楚为什么这个 next() 调用无法编译。有人可以为我描述这种行为吗?

编辑原件以进行模板化,因为这似乎很重要。

编辑以进一步澄清:这是一个编译时问题,而不是运行时问题。SomethingThatExtendsA() 的实现;在这种情况下,在编译时应该是无关紧要的。

4

3 回答 3

5

所以我们有这个代码:

public abstract class A<T> implements Iterator<B> {}
[...]
A a = new SomethingThatExtendsA();
a.next();

A是泛型类型,但您已a使用原始类型定义。忽略右边的=,我们只对静态类型感兴趣:

A/*<Something>*/ a = ...;

编译器应该在这里给你警告。(至少相对较新的 javac 版本会这样做 - rawtypesOracle javac 中的警告。)注意编译器的警告。(javac 不发出警告不是很好吗?)

所以现在我们处于一种a既是 raw 又是Iterator<B>. 这是一个非常令人困惑的情况,只有令人难以置信的困难含义。我们甚至不应该这样做——我们应该避免混合泛型和原始类型。因此 Java 语言规范采取了简单的方法并丢弃了部分泛型类型信息。

So, don't mix raw and generic types. Just use all generics and you should be fine.

于 2012-07-11T23:33:38.690 回答
0
public abstract class A implements Iterator<B> {}
class B {}
class SomethingThatExtendsA extends A {
// implement A methods
}
A a = new SomethingThatExtendsA();
a.next();

此代码非常正确并返回 B 对象。可能你在SomethingThatExtendsA课堂上错过了什么。

通过调用来测试它:

B b1 = new Object();  // compilation error
B b2 = a.next(); // all is OK

更新:将 SomethingThatExtendsA中的签名从更改 public Object next() { }public B next() {}

于 2012-07-11T23:12:33.560 回答
0

The SomethingThatExtendsA class is a red herring here. You get the same problem with

List<String> list = new ArrayList<String>();
list.add("foo");
Iterator iterator = list.iterator(); // you should get a warning on this line...
String foo = iterator.next(); // ... and a compile error on this line

The issue is that raw types are a horrible ugly hack for backwards compatibility only which cause all the generics around them to stop working. Specifically, Iterator is not the same type as Iterator<String>, Iterator<Object>, or even Iterator<?>. Instead, Iterator means "the Iterator class I would have got if I had compiled with a pre-generics version of Java". Since the pre-generics version of Iterator always returned Object, then that's what you get. And you can't assign a value of type Object to a more specific type (like String, or your type B) without a cast.

The Java Language Specification says this:

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

于 2012-07-12T00:31:42.077 回答