如何初始化ArrayList和HashMap?

3

假设我想创建一个数字的 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


4
你的第一个和第二个例子似乎是一样的? - snozza
我的错,我改正了我的问题。 - SJ19
1
关于第三个选项:请参见什么是原始类型,为什么我们不应该使用它? - Jesper
4个回答

7

最佳方式是:

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

让我们看看其他几个例子: private static ArrayList<Integer> numbers = new ArrayList<Integer>();使用了一个特定的类作为类型,这是不鼓励使用的,除非你需要访问ArrayList特定的方法(我不知道有哪些)。 private static ArrayList<Integer> numbers = new ArrayList();是不安全的类型,你的IDE应该在这一行上给出警告。

请问,您能详细解释一下为什么最后一个案例是类型不安全的吗?我该怎么做才能得到一个错误? - ka4eli
私有静态ArrayList<Integer> numbers = new ArrayList(); 是类型不安全的,如果您的IDE应该在这一行上警告您。实际上,如果您使用<>(),Android Studio会发出警告,建议您仅使用(). - Tim
1
@ka4eli,在这种特定情况下并不重要。然而在其他一些情况下(例如,如果类型参数受限或者您使用依赖于类型参数的构造函数参数),它会产生不同的结果。 - Tagir Valeev

3
你应该使用左侧的界面:
private static List<Integer> numbers = new ArrayList<>();

除非您真正需要该数据结构的特定方法。
IntelliJ IDEA建议您使用该结构,因为您正在使用JDK 1.7.x(或更高版本),并且没有必要再次指定类型,因为编译器可以从上下文中推断类型参数(同样适用于Java 7及更高版本)。

2
给出的所有示例将编译为相同的字节码不会影响后续类型检查。使用一个或另一个的原因是避免烦人的警告。
  • new ArrayList();非泛型的方式。编译器会警告你,因为你没有关注泛型(并且可能分配了一个带有除Integer之外的元素的ArrayList)。
  • new ArrayList<Integer>(); 是泛型的方式,但在编译器足够聪明以自行推断元素类型之前。因此,它会警告您,因为它比必要的更冗长。
  • new ArrayList<>(); 是当前首选的方式(感谢Java 7中引入的类型推断请参见相关SO问题)。除非你必须处理旧编译器,否则就选择这种方式。
也许一个有趣的问题是为什么使用类型推断时new ArrayList<>();是最好的,而new ArrayList();则不是。

1
第一个例子是正确的,你提供了所有需要的东西。但这也意味着你重复了参数类型的定义。
然后,在Java 1.7(或者可能是1.8,不太确定)中引入了缩短版本 - 所以如果你定义了ArrayList<Integer> numbers,就不需要重复定义ArrayList应该为Integer创建,并且你只需保留<>。这有时被称为钻石符号,它指示编译器使用与字段定义相同的数据类型。因此,它的行为与第一个例子完全相同,但无需重复关于数据类型的信息。
你最后给出的情况有些不同,因为你创建了一个没有指定数据类型的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相当)的编程语言正在做什么。 - x80486
@ɐuıɥɔɐɯ 你为什么这么想呢?我的意思是,我不想争论,只是好奇你的想法。这种“技巧”似乎被广泛使用,所以我想知道你在哪里看到问题。另外,我并不是说“到处都要这样做”,说“尽可能多地做”时,我认为读者会运用常识 :-) - Sva.Mu
只是一个“提示”;我也不争论。这种“技巧”被广泛使用(和滥用)……问候! - x80486

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接