为什么不需要声明 List 实现?

Why is declaring List implementation not needed?

我正在使用 returns 类型 List<> 的方法,然后我可以调用 List 上的方法:

List<Artist> artists = artistsPager.artists.items;
artists.add(new Artist());

要明确 artistsPager.artists.items 返回类型 List<Artist>

因为 List 只是一个接口,编译器如何让我使用这个 artists 对象,List<> 不是总是需要一个实现,比如 ArrayList?

例如,编译器不会让我执行以下操作,因为 "List is abstract; cannot be instantiated":

List<Integer> list = new List<Integer>();

artistsPager.artists.itemsnew List<Integer>() 有何不同?

对于那些好奇的人,这来自 Java Web API wrapper for Android。非常感谢所有帮助。

我不认为这是与此 question 的重复,因为即使答案相同,产生它们的问题也不同。另一个问题是询问类型 ListArrayList 之间的区别,而我的问题是想知道为什么编译器在 List 的实现被隐藏时没有抱怨。

我同意将此标记为重复项以引导未来用户解决该问题,但我认为不应将其关闭,因为我认为此处的答案对其他用户非常有帮助。

How is artistsPager.artists.items any different than new List<Integer>()?

artistsPager.artists.itemsList<> 类型的字段。在代码的某处,它一定是用 ArrayList.

这样的具体实现实例化的

new List<Integer>()是构造函数调用,无效,因为List是接口。

这意味着在某处创建了具体列表(例如,ArrayList)。

你只知道创建的列表正在实现List接口的方法,允许你使用这些方法。

以这个例子为例,对用户隐藏具体的 LinkedList

public static List<Integer> makeListOfInts(){
    return new LinkedList<Integer>(){
        {
            add(1);
            add(2);
        }
    }
}

我可以很容易地被替换为 ArrayList:

public static List<Integer> makeListOfInts(){
    return new ArrayList<Integer>(){
        {
            add(1);
            add(2);
        }
    }
}

函数的用户只知道返回了 List,但不知道列表的具体类型。它只能使用来自 List 接口的函数,而不是来自所选特定实现的函数。

doesn't a List<> always need an implementation, like ArrayList<>?

是的,您需要一个实现才能创建一个实例。但是,编译器知道两件事:

  • 它知道你已经创建了一些实例,并分配给items,并且
  • 它知道您分配给 items 的任何内容都实现了 List<> 接口

知道这两件事足以让编译器让您对声明为接口类型的变量调用 add。通过这种方式,您的 代码不需要关心您获得的是什么实现 - ArrayList<>LinkedList<> 或您开发的一些自定义实现:您的代码将工作与他们所有人。

请注意,通过接口类型引用对象的做法是可取的。它被称为编程到接口。它允许您隐藏实现细节,并在以后为不同的实现交换对象。