【问题标题】:Best way to initialize ArrayList and HashMap?初始化 ArrayList 和 HashMap 的最佳方法?
【发布时间】:2015-12-02 03:32:24
【问题描述】:

假设我想为数字创建一个ArrayList。我的学习方式是这样的:

private static List<Integer> numbers = new ArrayList<Integer>();

但 IntelliJ IDEA 想将其更正为

private static List<Integer> numbers = new ArrayList<>();

然后我发现这也有效:

private static List<Integer> numbers = new ArrayList();

现在我很困惑,最好的方法是什么?有什么区别。同样的问题也适用于HashMap。

【问题讨论】:

标签: java generics arraylist data-structures intellij-idea


【解决方案1】:

最好的办法是:

private static List<Integer> numbers = new ArrayList<>(); // Java 7
private static List<Integer> numbers = new ArrayList<Integer>(); // Java 6

让我们看看其他例子:

private static ArrayList&lt;Integer&gt; numbers = new ArrayList&lt;Integer&gt;(); 使用特定的类作为类型,除非您需要访问特定于 ArrayList 的方法(我不知道),否则不建议这样做

private static ArrayList&lt;Integer&gt; numbers = new ArrayList(); 是类型不安全的,您的 IDE 应该在这一行给您一个警告。

【讨论】:

  • 拜托,你能更详细地解释一下为什么最后一种情况是类型不安全的吗?我应该怎么做才能得到错误?
  • 私有静态 ArrayList numbers = new ArrayList();是类型不安全的,如果你的 IDE 应该在这一行给你一个警告。 实际上,如果你使用&lt;&gt;(),android studio 会给出一个警告,建议你只使用()
  • @ka4eli,在这种特殊情况下,这并不重要。但是在其他一些情况下(例如,如果类型参数是有界的,或者您使用依赖于类型参数的构造函数参数),它会有所不同。
【解决方案2】:

您应该使用左侧的界面:

private static List<Integer> numbers = new ArrayList<>();

除非您确实需要该数据结构的任何特定方法。

IntelliJ IDEA 建议您使用该构造,因为您使用的是 JDK 1.7.x(或更高版本)并且无需再次指定 type 因为编译器可以infer the type arguments from the context(再次来自Java 7 和/或更高版本)。

【讨论】:

    【解决方案3】:

    给出的所有示例都将编译为相同的字节码,并且不影响后续的类型检查。使用一个或另一个的原因是避免烦人的警告。

    • new ArrayList(); 是 pre-generics 方式。编译器会警告您,因为您不关心泛型(并且可能会使用 Integer 以外的元素分配 ArrayList)。
    • new ArrayList&lt;Integer&gt;(); 是泛型方式,但在编译器足够聪明地推断自身元素类型。因此它会警告您,因为它过于冗长。
    • new ArrayList&lt;&gt;(); 是目前首选的方式(感谢 Java 7 中引入的 Type Inference (see related SO question))。除非您必须处理较旧的编译器,否则请使用它。

    也许一个有趣的问题是为什么 new ArrayList&lt;&gt;(); 是最好的(类型推断)但 new ArrayList(); 不是。

    【讨论】:

      【解决方案4】:

      第一个例子是正确的,你提供了所需的一切。但这也意味着你重复了参数类型的定义。

      然后,在 Java 1.7(或者可能是 1.8,不太确定)中,他们引入了缩短版本 - 因此,如果您定义 ArrayList&lt;Integer&gt; numbers,则无需为 Integer 创建重复定义 ArrayList你只要把&lt;&gt;留在那里。这有时称为菱形表示法,它指示编译器使用与您用于字段定义的数据类型完全相同的数据类型。因此,它的行为与第一个示例完全相同,但不需要复制有关数据类型的信息。

      当您创建一个没有指定数据类型的ArrayList 时,您遇到的最后一种情况有些不同。这可能有点危险,因为它允许您编写以下代码:

      List listAnything = new ArrayList();
      listAnything.add("string");
      listAnything.add(42);
      listAnything.add(false);
      
      List<Integer> listInteger = listAnything;
      

      上面列出的代码编译得非常好,尽管有一些关于未经检查的转换和使用原始类型的警告。您不再保证listInteger 只包含整数。

      另外,这里有一个警告词——你应该在你的代码中尽可能地依赖抽象。我的意思是使用接口或抽象类而不是具体类来定义您的字段。这样的代码更易于阅读和维护:

      ArrayList<Integer> list = new ArrayList<>(); // this is not wrong...
      List<Integer> list = new ArrayList<>(); // ...but this is better
      

      【讨论】:

      • “你应该在你的代码中尽可能多地依赖抽象”...注意这一点,大约 90% 的时候这不是真的;尽管在现实生活中这很有用(我在这里不是在谈论 API 开发)。如今,Java 正因此而臃肿……看看许多其他(与 Java 相比)编程语言在做什么。
      • @ɐuıɥɔɐɯ 你为什么这么认为?我的意思是,我不想争论,只是好奇你在想什么。这种“技术”似乎被广泛使用,所以我想知道你在哪里发现了它的问题。另外,我并不是说“随时随地都这样做”,而是说“尽可能多”,我认为读者会使用常识:-)
      • 只是一个“提示”;我也不争。它被广泛使用(和滥用)的“技术”......问候!
      猜你喜欢
      • 2011-11-24
      • 2018-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-11
      • 2015-07-16
      • 1970-01-01
      • 2010-09-17
      相关资源
      最近更新 更多