Java中List引用调用LinkedList特有方法报错及相关疑问
这三个问题本质上都和Java的编译时类型与运行时类型的差异有关,咱们逐个拆解清楚:
1. 为什么用List声明的变量无法调用LinkedList的特有方法?
Java编译器检查方法调用时,只认变量的编译时类型(也就是你声明变量时写的List<String>),完全不管它实际指向的对象是什么(运行时类型是LinkedList<String>)。
addLast()和removeLast()是LinkedList类独有的方法,并没有在List接口中定义。编译器认为List类型的变量只能调用List接口里声明的方法,所以直接抛出“找不到符号”的编译错误。
如果确实需要调用这些特有方法,你可以做显式向下转型,把List类型转成LinkedList类型:
List<String> list = new LinkedList<>(); ((LinkedList<String>) list).addLast("string"); // 显式转型后即可正常调用
不过转型前最好用instanceof做类型检查,避免出现ClassCastException。
2. 明明通过instanceof判断是LinkedList实例,为什么还是不能直接调用特有方法?
instanceof是运行时才会执行的类型判断逻辑,而方法调用的合法性是在编译阶段就确定的。
编译器不会因为你写了if (list instanceof LinkedList)就自动把list的编译时类型改成LinkedList,它依然只认List类型。要调用特有方法,必须在判断后显式转型:
List<String> list = new LinkedList<>(); if (list instanceof LinkedList) { LinkedList<String> linkedList = (LinkedList<String>) list; linkedList.addLast("test"); // 转型后变量的编译时类型是LinkedList,可调用特有方法 }
3. List接口没有forEach方法,为什么实例化后能调用?
这个和Lambda表达式没有直接关系,核心是Java 8引入的默认方法(Default Method)机制。
List接口继承自Collection,而Collection又继承自Iterable接口。在Java 8中,Iterable接口新增了一个默认方法forEach():
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
默认方法会被所有实现该接口的子类继承,所以即使List接口自己没定义forEach,它的实现类(比如ArrayList、LinkedList)也能通过继承Iterable的默认方法来使用这个功能。
内容的提问来源于stack exchange,提问作者OneFlowerOneWorld

