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

时间:2010-04-09 21:20:46

标签: java generics inheritance inner-classes

使用内部类编译泛型类时遇到问题。该类扩展了泛型类,也就是内部类。

这里实现的界面:

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)。不,我无法将其转换为静态内部类。

2 个答案:

答案 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> { 
    }
}