在用bounds扩展的泛型内部类的继承上编译错误

Arn*_*ter 9 java generics inheritance inner-classes

编译具有内部类的泛型类时遇到问题.该类扩展了一个泛型类,也就是内部类.

这里实现的接口:

public interface IndexIterator<Element>
    extends Iterator<Element>
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

通用超类:

public abstract class CompoundCollection<Element, Part extends Collection<Element>>
    implements Collection<Element>
{
  ...

  protected class CompoundIterator<Iter extends Iterator<Element>>
      implements Iterator<Element>
  {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

具有编译器错误的通用子类:

public class CompoundList<Element>
    extends CompoundCollection<Element, List<Element>>
    implements List<Element>
{
  ...

  private class CompoundIndexIterator
      extends CompoundIterator<IndexIterator<Element>>
      implements IndexIterator<Element>
  {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

错误是:

type parameter diergo.collect.IndexIterator<Element> is not within its bound
       extends CompoundIterator<IndexIterator<Element>>
                                             ^
Run Code Online (Sandbox Code Playgroud)

怎么了?代码用eclipse编译,但不用java 5编译器编译(我在mac和eclipse 3.5上使用ant和java 5).不,我无法将其转换为静态内部类.

mer*_*ike 8

Java语言规范,§8.1.3,定义了子类内类型如下的语义:

此外,对于C的每个超类S本身是类SO的直接内部类,有一个与i关联的SO实例,称为关于S的直接封闭的i实例.对象的直接封闭实例关于其类的直接超类(如果有的话)是在通过显式构造函数调用语句调用超类构造函数时确定的.

请注意,封闭实例仅描述为特定,而不是特定类型.由于泛型类型的所有实例共享同一个类,因此以下代码是合法的:

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> {}
}
Run Code Online (Sandbox Code Playgroud)

当然,这可以用来打破类型不变(即导致堆污染):

    StrangeSub ss = new StrangeSub();
    ss.e = 42;
    String s = ss.new StrangeSubInner().e();
Run Code Online (Sandbox Code Playgroud)

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> {}
                                                                       ^
Run Code Online (Sandbox Code Playgroud)

显然,编译器并不是简单地检查类型参数来对抗内部的超类'类型参数绑定,就像eclipse那样.在这种情况下,我认为这是正确的做法,因为声明显然是不安全的.但是,Sun编译器同样拒绝以下声明,即使它是可证明类型安全的:

class StrangeSub extends Base<Integer> {
    protected class StrangeSubInner extends BaseInner<Integer> {}
}
Run Code Online (Sandbox Code Playgroud)

我的预感是,验证这种菱形类型限制的一致性超出了Sun编译器的能力,因此这些结构被简单地拒绝了.

要解决这个限制,我首先尝试去掉类型参数CompoundIterator.