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 是一种静态类型语言。这意味着编译器会查看变量的声明类型(而不是变量内部的对象)来决定该方法是否存在。
声明的类型
List
没有这些方法。它们已添加到 LinkedList
(来自 Deque
接口,用于“支持两端元素插入和删除的线性集合”)
我了解到将列表放在左侧更好。
是的,这就是所谓的“编码到接口”。它避免了您编写仅适用于该接口的特定实现的代码,并且可以在不更新调用代码的情况下更改实现。
但只有当界面提供你需要的一切时它才有效。
在您的情况下,您想要使用
addLast
,它不是通用 List
界面的一部分。所以你必须使用Deque
提供的接口(或者直接使用LinkedList
)。
中有forEach
方法,但ArrayList
中没有。List
forEach
是由 Iterable
定义的,它是所有这些东西的超级接口。因此,它也可以在 List
中使用。
如果是
的实例,为什么不能调用LinkedList
中声明和定义的方法?LinkedList
再次强调:静态类型。变量内的实际运行时实例很可能比变量声明的类型更具体。但是编译器在编译时只能进行静态分析,即查看源代码以及方法、字段和变量的声明类型,而不能查看程序执行期间发生的任何事情。
Java List 接口没有定义addLast 或removeLast 方法。由于您将变量声明为 List 而不是 LinkedList,因此您只能访问 List 接口上定义的成员。请参阅 List 文档 和 LinkedList 文档
嗯,只是因为 java.util.List 中没有声明“addLast()”方法,编译器只知道变量列表是 java.util.List 的实例,它会尝试查找名为 addLast 的方法() 在 List 中却什么也没得到,于是就惊慌了。
而且看来你可能需要更多地了解Java的继承和多态系统。
您给出的声明类型是 List,分配的类型是
LinkedList
。虽然对象是 LinkedList
,但它只支持声明类型中存在的方法,在您的情况下它是 List,它不附带仅特定于 LinkedList
的方法。 List 是一个 Interface
,也由 ArrayList<>
实现。现在,如果我们将这些方法保留在接口中,那么每个实现类也实现这些方法,因此就没有单一责任和关注点分离的意义。
只是因为 java.util.List 中没有声明“addLast()”方法,编译器只知道变量列表是 java.util.List 的实例,并且会尝试查找名为 addLast() 的方法在List中却什么也没得到,所以很惊慌。