使用内部类编译泛型类时遇到问题。该类扩展了泛型类,也就是内部类。
这里实现的界面:
public interface IndexIterator<Element>
extends Iterator<Element>
{
...
}
通用超类:
public abstract class CompoundCollection<Element, Part extends Collection<Element>>
implements Collection<Element>
{
...
protected class CompoundIterator<Iter extends Iterator<Element>>
implements Iterator<Element>
{
...
}
}
带有编译器错误的通用子类:
public class CompoundList<Element>
extends CompoundCollection<Element, List<Element>>
implements List<Element>
{
...
private class CompoundIndexIterator
extends CompoundIterator<IndexIterator<Element>>
implements IndexIterator<Element>
{
...
}
}
错误是:
type parameter diergo.collect.IndexIterator<Element> is not within its bound
extends CompoundIterator<IndexIterator<Element>>
^
有什么问题?代码用eclipse编译,但不用java 5编译器编译(我在mac和eclipse 3.5上使用ant和java 5)。不,我无法将其转换为静态内部类。
答案 0 :(得分:8)
Java Language Specification, §8.1.3定义子类化内部类型的语义,如下所示:
此外,对于每个超类S C本身就是一个直接的内部阶级 在SO类中,有一个实例 与我联系,称为 立即附上我的实例 关于S.立即 用...包围对象的实例 尊重其班级的直接 超类,如果有的话,确定何时 调用超类构造函数 通过显式构造函数调用 言。
请注意,封闭实例仅描述为特定的类,而不是特定的类型。由于泛型类型的所有实例共享同一个类,因此以下代码是合法的:
class Base<E> {
E e;
protected class BaseInner<I extends E>{
E e() { return e; }
}
}
class StrangeSub extends Base<Integer> {
protected class StrangeSubInner extends Base<String>.BaseInner<String> {}
}
当然,这可以用来打破类型不变量(即导致堆污染):
StrangeSub ss = new StrangeSub();
ss.e = 42;
String s = ss.new StrangeSubInner().e();
eclipse编译器将Java语言规范作为面值,并接受上述代码,甚至不发出“未经检查”的警告。虽然技术上符合JLS,但这显然违反了其意图。
Sun Java Compiler拒绝声明StrangeSubInner
:
Test.java:32: type parameter java.lang.String is not within its bound
protected class StrangeSubInner extends Base<String>.BaseInner<String> {}
^
显然,编译器并不是简单地检查类型参数对内部的超类'类型参数绑定,就像eclipse那样。在这种情况下,我认为这是正确的做法,因为声明显然是不安全的。但是,Sun编译器同样拒绝以下声明,即使它是可证明类型安全的:
class StrangeSub extends Base<Integer> {
protected class StrangeSubInner extends BaseInner<Integer> {}
}
我的预感是,验证这种菱形类型限制的一致性超出了Sun编译器的能力,因此这些结构被立即拒绝了。
要解决此限制,我首先尝试将类型参数移除到CompoundIterator
。
答案 1 :(得分:1)
也许这没有太大进展,但我设法将上面的代码减少到以下仍然表现出相同奇怪行为的代码:
class Base<E> {
protected class BaseInner<I extends E>{
}
}
class Sub<E> extends Base<E>{
class SubInner extends BaseInner<E> {
}
}