代码之家  ›  专栏  ›  技术社区  ›  Arne Burmeister

泛型内类带界扩展继承的编译错误

  •  9
  • Arne Burmeister  · 技术社区  · 16 年前

    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>>
                                                 ^
    

    2 回复  |  直到 16 年前
        1
  •  8
  •   meriton    16 年前

    这个 Java Language Specification, §8.1.3 ,定义子类化内部类型的语义,如下所示:

    它本身就是一个直接的内部类 所以,有一个 所以和我联系在一起,被称为 立即包含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语言规范作为面值,接受上述代码,甚至不发出“unchecked”警告。虽然可以说在技术上符合JLS,但这显然违背了它的意图。

    sunjava编译器拒绝 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

        2
  •  1
  •   Eyal Schneider    16 年前

    也许这并没有多大的进步,但我设法将上面的代码缩减为以下仍然表现出相同怪异行为的代码:

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