1. ホーム
  2. java

[解決済み] なぜワイルドカードジェネリックで複数のインターフェースを持つことができないのですか?

2023-07-24 03:12:12

質問

Java の汎用型には直感に反するような性質がいろいろあることは知っています。特に理解できないものがあり、誰かが私に説明してくれることを期待しています。クラスやインターフェースの型パラメータを指定するとき、複数のインターフェースを実装しなければならないように、クラスやインターフェースを public class Foo<T extends InterfaceA & InterfaceB> . しかし、実際のオブジェクトをインスタンス化する場合、これはもううまくいきません。 List<? extends InterfaceA> は問題ありませんが List<? extends InterfaceA & InterfaceB> はコンパイルに失敗します。次の完全なスニペットを考えてみましょう。

import java.util.List;

public class Test {

  static interface A {
    public int getSomething();
  }

  static interface B {
    public int getSomethingElse();
  }

  static class AandB implements A, B {
    public int getSomething() { return 1; }
    public int getSomethingElse() { return 2; }
  }

  // Notice the multiple bounds here. This works.
  static class AandBList<T extends A & B> {
    List<T> list;

    public List<T> getList() { return list; }
  }

  public static void main(String [] args) {
    AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
    foo.getList().add(new AandB());
    List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
    // This last one fails to compile!
    List<? extends A & B> foobar = new LinkedList<AandB>();
  }
}

のセマンティクスは bar のセマンティクスはよく定義されているはずです。1つだけでなく2つの型の交差を許可することによって、型の安全性が失われるとは思えません。しかし、何か説明があるはずです。誰かそれが何であるか知っていますか?

どのように解決するのですか?

興味深いことに、インターフェイス java.lang.reflect.WildcardType は、ワイルドカードの arg に対して上限と下限の両方をサポートし、それぞれに複数の上限を含めることができるようです。

Type[] getUpperBounds();
Type[] getLowerBounds();

これは言語が許容する範囲をはるかに超えています。ソースコードに隠されたコメントがあります。

// one or many? Up to language spec; currently only one, but this API
// allows for generalization.

インターフェースの作者は、これは偶発的な制限であると考えているようです。

あなたの質問に対する定型的な答えは、ジェネリクスは現状ですでに複雑すぎる、ということです。

ワイルドカードが複数の上限を持つことを許可するには、仕様をスキャンして、システム全体がまだ動作することを確認する必要があります。

私が知っている1つの問題は、型推論になります。現在の推論ルールは、単に交差型を扱うことができません。制約を減らすためのルールはありません。 A&B << C . もし、それを

    A<<C 
  or
    A<<B

現在の推論エンジンは、このような分岐を可能にするために、大きなオーバーホールをしなければなりません。しかし、本当に深刻な問題は、これは複数の解決策を可能にしますが、他のものより1つを好む正当な理由がないことです。

しかし、推論は型安全性に不可欠なものではありません。この場合、単に推論を拒否し、プログラマに明示的に型引数を埋めるように要求することができます。したがって、推論の難しさはインターセクション型に対する強い議論ではありません。