3
@Test
public void TypeInferenceTest() {
    inference();
    uncheckedAssignment();
    explicit();
}

private void inference() {
    ArrayList<String> strings = new ArrayList<>();
    strings.add("abc");
    String s = strings.get(0);

    assertThat(s, is("abc"));
}

private void uncheckedAssignment() {
    ArrayList<String> strings = new ArrayList();
    strings.add("abc");
    String s = strings.get(0);

    assertThat(s, is("abc"));
}

private void explicit() {
    ArrayList<String> strings = new ArrayList<String>();
    strings.add("abc");
    String s = strings.get(0);

    assertThat(s, is("abc"));
}

上記のコードでは、リストをインスタンス化するために、型推論、オープン ジェネリック型、クローズ ジェネリック型の 3 つの方法を使用しました。

しかし、生成されたバイトコードを JD-GUI を使用して逆コンパイルすると、次のようになります。

  @Test
  public void TypeInferenceTest() {
    inference();
    uncheckedAssignment();
    explicit();
  }

  private void inference() {
    ArrayList strings = new ArrayList();
    strings.add("abc");
    String s = (String)strings.get(0);

    Assert.assertThat(s, Matchers.is("abc"));
  }

  private void uncheckedAssignment() {
    ArrayList strings = new ArrayList();
    strings.add("abc");
    String s = (String)strings.get(0);

    Assert.assertThat(s, Matchers.is("abc"));
  }

  private void explicit() {
    ArrayList strings = new ArrayList();
    strings.add("abc");
    String s = (String)strings.get(0);

    Assert.assertThat(s, Matchers.is("abc"));
  }

彼らは同じバイトボットを生成したようです。

では、いつ、なぜ他の 2 つの代わりに型推論を使用する必要があるのでしょうか?

4

3 に答える 3

4

他の人は、同じコードを生成する理由をカバーしています。したがって、実際の質問に答えるには、短い答えはこれを好むことです:

   ArrayList<String> strings = new ArrayList<>();

これよりも簡潔ですが、同じ意味を (人間とコンパイラーに) 伝えているためです。

   ArrayList<String> strings = new ArrayList<String>();

ただし、次のような警告が不必要に発生することは避けます。

   ArrayList<String> strings = new ArrayList();

簡潔にするために、これは:

   ArrayList<String> strings = new ArrayList<String>();

それは悪いことではありませんし、それを入力することに実際の害はありません (結局のところ、私たちは皆、何年もそれを行ってきました)。しかし、あなたが次のようなものを書くことになったら:

   Map<String, Map<Widget<Spork>, Bar<Llama>>> myMap = new HashMap<>();

これを 2 回入力する必要がある場合は、はるかに退屈になります。

<String, Map<Widget<Spork>, Bar<Llama>>>
于 2013-06-09T05:40:04.283 に答える
2

あなたの例が示すように、Javaジェネリックは型消去によって実装され、ジェネリックコードは実行時の非ジェネリックコードと何ら変わりはありません。これにより、ジェネリックは純粋にコンパイル時の機能になり、開発者の利益のために型の安全性が追加されました。

あなたの例の場合、new ArrayList()new ArrayList<String>()、およびnew ArrayList<>()- 重要なのは、割り当てられる変数の型だけです。レガシーコードのように見え、別の開発者を混乱させる可能性があるため、使用new ArrayList()はまだ推奨されていません。これにより、コンパイラ/IDE が標準の「生の型」の警告を表示するため、注意が散漫になります。しかし、少なくとも引数のないコンストラクターの場合はそれだけです。

ただし、型引数を提供するか、型推論を使用することは、ジェネリック引数を取るコンストラクターにとって非常に重要です。次の例を検討してください。

Collection<Integer> ints = Arrays.asList(1, 2, 3);

List<String> strings1 = new ArrayList(ints);         // compiles!
List<String> strings2 = new ArrayList<String>(ints); // won't compile
List<String> strings3 = new ArrayList<>(ints);       // won't compile

new ArrayList<>(ints)overを使用する理由についてはnew ArrayList<String>(ints)、あまり冗長ではなく、代入先の変数で既に指定されているジェネリック型を繰り返さないようにします。

于 2013-06-09T05:35:02.040 に答える
2

型推論は、パラメータ化された型をインスタンス化するための不必要に長い方法のショートカットにすぎません。ジェネリックは引き続き型消去によって実装されるため、バイトコードには生の型しかありません。

于 2013-06-09T05:04:58.880 に答える