9

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

这里实现的接口:

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

4

2 回答 2

8

Java 语言规范第 8.1.3 节定义了子类化内部类型的语义,如下所示:

此外,对于 C 的每个超类 S,它本身就是类 SO 的直接内部类,都有一个与 i 相关联的 SO 实例,称为 i 相对于 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 编译器拒绝以下声明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.

于 2010-04-10T00:14:15.607 回答
1

也许这并没有太大进展,但我设法将上面的代码简化为以下仍然表现出相同奇怪行为的代码:

class Base<E> { 
    protected class BaseInner<I extends E>{
    } 
} 

class Sub<E> extends Base<E>{ 
    class SubInner extends BaseInner<E> { 
    }
} 
于 2010-04-09T22:31:50.827 回答