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でJava 5でantを使用します)。いいえ、静的内部クラスに変換できません。

4

2 に答える 2

8

Java 言語仕様 §8.1.3では、内部型のサブクラス化のセマンティクスを次のように定義しています。

さらに、それ自体がクラス SO の直接の内部クラスである C のすべてのスーパークラス S に対して、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> {}
}

もちろん、これを使用して型の不変条件を破ることができます (つまり、ヒープ汚染を引き起こします)。

    StrangeSub ss = new StrangeSub();
    ss.e = 42;
    String s = ss.new StrangeSubInner().e();

Eclipse コンパイラーは、Java 言語仕様を額面通りに受け取り、「チェックされていない」警告を出すことさえせずに上記のコードを受け入れます。間違いなく技術的には JLS に準拠していますが、これは明らかに JLS の意図に違反しています。

Sun Java コンパイラは with の宣言を拒否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 に答える