在实现Iterator <e>的抽象类上调用next()会返回Object而不是E </e>

时间:2012-07-11 22:57:55

标签: java generics

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

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

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

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

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

编辑原文是模板化的,因为这似乎很重要。

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

3 个答案:

答案 0 :(得分:5)

所以我们有这个代码:

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

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

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

编译器应该在这里给你警告。 (至少相对较新版本的javac会在Oracle javac中发出rawtypes警告。)注意编译器的警告。 (当javac没有发出警告时,这不是很好吗?)

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

因此,不要混合原始类型和泛型类型。只需使用所有泛型,你应该没事。

答案 1 :(得分: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() {}

答案 2 :(得分:0)

SomethingThatExtendsA课程在这里是一个红鲱鱼。

会遇到同样的问题
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

问题是原始类型是一种可怕的丑陋黑客攻击,只会导致它们周围的所有泛型停止工作。具体而言,Iterator Iterator<String>Iterator<Object>甚至Iterator<?>的类型不同。相反,Iterator表示“如果我使用预先泛型版本的Java编译,我将获得的Iterator类”。由于Iterator的pre-generics版本始终返回Object,所以这就是你得到的。而且,如果没有强制转换,您就无法将类型Object的值分配给更具体的类型(如String或类型B)。

Java语言规范说:

  

原始类型的使用仅允许作为遗留代码兼容性的让步。在将通用性引入Java编程语言之后编写的代码中使用原始类型强烈建议不要未来版本的Java编程语言可能会禁止使用原始类型