Java 找不到像 addFirst 或 addLast 这样的方法

问题描述 投票:0回答:5
import java.util.List;
import java.util.LinkedList;
class Test {
    public static void main(String[] args) {
        List<String> list = new LinkedList<String>();
        list.addLast("string");
        list.removeLast();
    }
}

当我编译代码时:

$ javac Test.java
Test.java:6: error: cannot find symbol
        list.addLast("string");
            ^
  symbol:   method addLast(String)
  location: variable list of type List<String>
Test.java:7: error: cannot find symbol
        list.removeLast();
            ^
  symbol:   method removeLast()
  location: variable list of type List<String>
2 errors

如果我实例化一个LinkedList,两边都是LinkedList,那么就不会出现错误。我了解到将列表放在左侧更好。为什么会发生这种事?

更新#1 如果变量

list
的类型是
List
,为什么下面的代码会打印
true
:

class Test {
    public static void main(String[] args) {
       List<String> list = new LinkedList<String>();
       System.out.println(list instanceof LinkedList);
    }
}

我从上面代码的结果中解释的是

list
LinkedList
的一个实例。如果它是
LinkedList
的实例,为什么它不能调用
LinkedList
中声明和定义的方法?

更新#2

forEach
中有
ArrayList
方法,但
List
中没有。为什么我仍然可以在
forEach
变量上调用
list
方法

List<String> list = new ArrayList<String>();

这和lambda表达式有关系吗?

java
5个回答
7
投票

为什么会发生这种事?

Java 是一种静态类型语言。这意味着编译器会查看变量的声明类型(而不是变量内部的对象)来决定该方法是否存在。

声明的类型

List
没有这些方法。它们已添加到
LinkedList
(来自
Deque
接口,用于“支持两端元素插入和删除的线性集合”)

我了解到将列表放在左侧更好。

是的,这就是所谓的“编码到接口”。它避免了您编写仅适用于该接口的特定实现的代码,并且可以在不更新调用代码的情况下更改实现。

但只有当界面提供你需要的一切时它才有效。

在您的情况下,您想要使用

addLast
,它不是通用
List
界面的一部分。所以你必须使用
Deque
提供的接口(或者直接使用
LinkedList
)。

forEach
中有
ArrayList
方法,但
List
中没有。

forEach
是由
Iterable
定义的,它是所有这些东西的超级接口。因此,它也可以在
List
中使用。

如果是

LinkedList
的实例,为什么不能调用
LinkedList
中声明和定义的方法?

再次强调:静态类型。变量内的实际运行时实例很可能比变量声明的类型更具体。但是编译器编译时只能进行静态分析,即查看源代码以及方法、字段和变量的声明类型,而不能查看程序执行期间发生的任何事情。


1
投票

Java List 接口没有定义addLast 或removeLast 方法。由于您将变量声明为 List 而不是 LinkedList,因此您只能访问 List 接口上定义的成员。请参阅 List 文档LinkedList 文档


0
投票

嗯,只是因为 java.util.List 中没有声明“addLast()”方法,编译器只知道变量列表是 java.util.List 的实例,它会尝试查找名为 addLast 的方法() 在 List 中却什么也没得到,于是就惊慌了。
而且看来你可能需要更多地了解Java的继承和多态系统。


0
投票

您给出的声明类型是 List,分配的类型是

LinkedList
。虽然对象是
LinkedList
,但它只支持声明类型中存在的方法,在您的情况下它是 List,它不附带仅特定于
LinkedList
的方法。 List 是一个
Interface
,也由
ArrayList<>
实现。现在,如果我们将这些方法保留在接口中,那么每个实现类也实现这些方法,因此就没有单一责任和关注点分离的意义。


0
投票

只是因为 java.util.List 中没有声明“addLast()”方法,编译器只知道变量列表是 java.util.List 的实例,并且会尝试查找名为 addLast() 的方法在List中却什么也没得到,所以很惊慌。

© www.soinside.com 2019 - 2024. All rights reserved.