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"));
}

上面的代码使用了三种方式来实例化一个列表:类型推断、开放泛型和封闭泛型。

但是如果我使用 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"));
  }

看起来他们生成了相同的 bytebote。

那么什么时候以及为什么我们应该使用类型推断而不是其他两个呢?

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<>();

如果您必须输入两次,这将变得更加乏味:

<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 回答