三种类型的数组列表声明之间有什么区别,为什么我们先编写接口然后在另一端实现类?

Ank*_*kur 2 java

我是 Java 的初学者。我有两个基本问题。

  1. 当我们将数组列表的声明写为

    1. List l=new ArrayList<String>();
    2. List<String> l=new ArrayList<String>();
    3. List<String> l=new ArrayList<>();

    我看到以上所有陈述都没有给出任何错误。当我们选择其中一种方法来声明任何集合时,它会产生什么不同?

  2. 当我们将集合初始化为

    1. List<String>l = new ArrayList<String>();

    所以如果我们像下面这样声明

    1. ArrayList<String> l= new ArrayList<String>();

    1 和 2 有什么区别,为什么我们在使用集合时主要选择 2?

Tob*_*ias 6

a) List l = new ArrayList<String>();与 相同List<Object> l = new ArrayList<String>();。这意味着该变量l是一个可以存储 any 的列表Object,但不仅仅是一个字符串。如果您想将它们用作字符串,您还需要转换列表的值。所以下面的代码会编译(这通常不是你想要的):

List l = new ArrayList<String>();
l.add("a string");//adding a String type is what is expected here
l.add(42);//adding an int is not realy expected here, but works
l.add(new Date());//also adding any other object is allowed

String s = (String) l.get(0);//s will be "a string"
String s2 = (String) l.get(1);//runtime error, since 42 can't be cast into a String
Run Code Online (Sandbox Code Playgroud)

b) List<String> l=new ArrayList<String>();表示该变量l是一个字符串列表,并且只接受字符串值。将下面的代码会导致编译器错误:

List<String> l = new ArrayList<String>();
l.add("a string");//adding a String type is what is expected here
l.add(42);//compiler error
l.add(new Date());//compiler error
Run Code Online (Sandbox Code Playgroud)

c) List<String> l=new ArrayList<>();基本相同List<String> l=new ArrayList<String>();。菱形运算符<>只是意味着编译器应该清楚,这里使用的是哪种类型,这样程序员就可以偷懒,让编译器来完成工作。


p) List<String>l = new ArrayList<String>();告诉编译器, l 是List类型。因此,如果您想为ArrayList变量 l分配 an ,这是允许的,然后如果您决定 aLinkedList更好,您仍然可以分配 aLinkedList并且它仍然可以工作,因为LinkedListArrayList都实现了接口List。所以以下代码将起作用

List<String> l = new ArrayList<String>();
//later on you decide to change the type (maybe for a better performance or whatever)
l = new LinkedList<String>();
//use the List l like nothing has changed. You just don't need to care.
Run Code Online (Sandbox Code Playgroud)

q) ArrayList<String> l= new ArrayList<String>();意味着,变量l是 anArrayList并且永远不能是任何其他List实现(如 a LinkedList),因此您无法轻松更改实现。因此,以下代码将无法编译:

List<String> l = new ArrayList<String>();
//later on you decide to change the type (maybe for a better performance or whatever)
l = new LinkedList<String>();//compiler error; now you need to change many parts of your code if you still want to change the type of l to a LinkedList
Run Code Online (Sandbox Code Playgroud)

因此通常p是更好的解决方案,因为您可以轻松更改代码。只有您需要调用不属于List接口的方法,例如方法ArrayList使用q可能需要它trimToSize方法。但这是一种非常罕见的情况。


概括:

在几乎所有情况下,使用p比使用q更好。
此外,在几乎所有情况下最好还是使用bc ^。无论您使用b还是c都没有那么重要。c只是短了一点。

  • `List l = new ArrayList&lt;String&gt;(); 与 List&lt;Object&gt; l = new ArrayList&lt;String&gt;()` 相同,这是不正确的!`List` 被称为*原始类型*,它与 `List&lt;Object&gt;` 不同。请注意如何从一个而不是另一个获得原始类型警告! (2认同)

Ste*_*n C 5

第1部分。

一种) List l = new ArrayList<String>();

b) List<String> l = new ArrayList<String>();

C) List<String> l = new ArrayList<>();

b) 和 c) 之间没有区别。

但是 a) 声明l原始类型。这是不鼓励的。使用时l,编译器不“知道”数组元素的类型:

  • 如果要将元素用作字符串,则需要对它们进行强制转换。
  • 它不会阻止您将不是字符串的内容放入列表中。哎呀!!!

第2部分。

p) List<String>l = new ArrayList<String>();

q) ArrayList<String> l = new ArrayList<String>();

不同之处在于lp)中的类型表示它可以是任何List实现,但在 q) 中它仅限于ArrayList和 子类型。

如果l只在本地使用,它可能没什么区别。但是如果l是你的 API 的一部分,或者如果你需要分配l一个不同的List值,你可能会遇到问题。例如,当您调用List.sublistan 时ArrayList,您返回的对象不是ArrayList!

所以......作为一般规则,p) 更好。

一般来说,最好是“编程到接口”(即 p)而不是实现(即 q)。