1

次のコードで奇妙な問題が発生しました(まあ、正確にはこのコードではありません):

public class CompilationProblems1 {

  static Box<Class<? extends AlcoholicBewerage>> brokenBoxOfOneBeer = boxOf(Beer.class);
  static Box<? extends Class<? extends AlcoholicBewerage>> boxOfOneBeer = boxOf(Beer.class);
  static Box<Class<? extends AlcoholicBewerage>> boxOfBeerAndVodka = boxOf(Beer.class, Vodka.class);

  interface AlcoholicBewerage {}

  class Beer implements AlcoholicBewerage {}

  class Vodka implements AlcoholicBewerage {}

  static class Box<T> {}

  static <E> Box<E> boxOf(E e) {
      return new Box<E>();
  }

  static <E> Box<E> boxOf(E e1, E e2) {
      return new Box<E>();
  }
}

最初の宣言brokenBoxOfOneBeerはコンパイルエラーを出します:

found   : lt.tool.CompilationProblems1.Box<java.lang.Class<lt.tool.CompilationProblems1.Beer>>
required: lt.tool.CompilationProblems1.Box<java.lang.Class<? extends   lt.tool.CompilationProblems1.AlcoholicBewerage>>
static Box<Class<? extends AlcoholicBewerage>> brokenBoxOfOneBeer = boxOf(Beer.class);

このエラーは、OpenJDK 6、Eclipse、およびIntelliJで発生します。これが型推論の制限であることを理解しています。

3番目のケース(boxOfBeerAndVodka)では、コンパイラーは2つのサブタイプから選択できるため、正しい共変型を推測できます。しかし、なぜコンパイラは最初の宣言をコンパイルできないのに、2番目の宣言は問題ないのでしょうか。

4

2 に答える 2

1

Beer.class型引数は、最初に実際の引数()に基づいて推測されます( §15.12.2.7)。実際の引数に基づいて型引数を推測できなかった場合は、コンテキスト(brokenBoxOfBeer)が考慮されます(§15.12.2.8)。

したがって、この問題は次のように回避できます。

static <X, E extends X> Box<X> boxOf(E e) {
  return new Box<X>();
}

編集:これは回避策であり、独自の問題が伴うことに注意してください。ネストされた呼び出しは正しく推測されなくなります。

Box<Box<Integer>> x = boxOf(boxOf(1)); // won't compile
于 2012-09-21T15:26:28.000 に答える
1

しかし、なぜコンパイラは最初の宣言をコンパイルできないのに、2番目の宣言は問題ないのでしょうか。

どちらの場合も、式のboxOf(Beer.class)タイプはBox<Class<Beer>>です。

  • Box<Class<? extends AlcoholicBewerage>>最初の宣言では、タイプが;である必要があります。Box<Class<Beer>>はのサブタイプではないため、Box<Class<? extends AlcoholicBewerage>>これは機能しません。(Class<Beer>はのサブタイプですがClass<? extends AlcoholicBewerage>、不変性のため、これはのサブタイプを必要としませ。)Box<Class<Beer>>Box<Class<? extends AlcoholicBewerage>>
  • 2番目の宣言では、タイプが必要Box<? extends Class<? extends AlcoholicBewerage>>です。これはタイプです。Class<Beer>はのサブタイプでありClass<? extends AlcoholicBewerage>、ergoはのBox<Class<Beer>>サブタイプですBox<? extends Class<? extends AlcoholicBewerage>>

つまり、次の場合とまったく同じことが宣言で発生します。

List<Object> foo = new ArrayList<String>(); // doesn't work
List<? extends Object> bar = new ArrayList<String>(); // works

Object代わりに、String別のレベルのジェネリック型があるため、より複雑に見えます。

于 2012-09-21T15:35:45.000 に答える