3
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();
    }
}

When I compile the code:

$ 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

If I instantiate a LinkedList with LinkedList on both sides, then there will be no errors. I have learned that putting List on the left side is better. Why did this happen?

Update #1 If the variable list is of type List, why does the following code print true:

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

What I interpret from the result of the above code is that list is an instance of LinkedList. If it's an instance of LinkedList, why can't it call methods declared and defined in LinkedList?

Update #2 There is forEach method in ArrayList but not in List. Why am I still be able to call forEach method on the list variable after I do

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

Does this have something to do with lambda expression?

  • 1
    The compiler's not the only one, the [JavaDoc for `List`](https://docs.oracle.com/javase/8/docs/api/java/util/List.html) fail to find them either. since `list` is just an instance of `List`, the functionality you're attempting to use isn't exposed to it. `addFirst` and `removeLast` are only defined as part of `LinkedList` (see the [JavaDocs](https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html)), so only variables who are of the type `LinkedList` can access them, try `LinkedList list = new LinkedList();` instead – MadProgrammer May 17 '18 at 03:19
  • 1
    addLast method is in LinkList class but not in List Interface use like this LinkedList list = new LinkedList(); – janith1024 May 17 '18 at 03:22
  • See also https://stackoverflow.com/questions/50268992/java-calling-a-subclass-method-from-superclass-variable/50269092#50269092 – Thilo May 17 '18 at 03:33

4 Answers4

7

Why did this happen?

Java is a statically typed language. This means that the compiler looks at the declared type of the variable (not the object that may be inside it) to decide if the method exists or not.

The declared type List does not have these methods. They have been added in LinkedList (and come from the Deque interface for "linear collections that support element insertion and removal at both ends")

I have learned that putting List on the left side is better.

Yes, this is called "coding to the interface". It avoids that you write code that only works with a specific implementation of that interface, and makes it possible to change the implementation without updating calling code.

But it only works if the interface provides everything you need.

In your case, you want to use addLast, which is not part of the general List interface. So you have to use the interface provided by Deque (or just LinkedList directly).

There is forEach method in ArrayList but not in List.

forEach is defined by Iterable which is the super-interface of all these things. As such, it is available in List as well.

If it's an instance of LinkedList, why can't it call methods declared and defined in LinkedList?

Again: static typing. The actual runtime instance inside the variable may very well be of a more specific type than the variable is declared to be. But the compiler at compile-time can only do static analysis, i.e. look at the source code and the declared types of methods, fields and variables, not at anything that happens during program execution.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Thank you very much! What confuses me now is that `list` turns out to be also of type `LinkedList`. Please see Update #1 in my edited question. – OneFlowerOneWorld May 17 '18 at 04:39
1

The Java List interface does not define an addLast or removeLast method. Since you declared your variable as a List rather than a LinkedList, you'll only be able to access the members defined on the List interface. See List documentation and LinkedList documentation

toltman
  • 467
  • 2
  • 6
0

Well , it just because there is no "addLast()" method stated in java.util.List , the compiler only konws that the variable list is a instance of java.util.List and it will try to find a method named addLast() in List but get nothing , so it alarmed.
And it seems that you may need to learn more about the Java's Inheritance and polymorphism system.

AnonymousX
  • 638
  • 7
  • 8
0

The declared type you have given is List and the assigned type is LinkedList. Though the object is of LinkedList, it will only support the method which are present in declaring type and in your case it's List,which doesn't come with the methods which are specific to LinkedList Only. List is an Interface and is implemented by ArrayList<> as well. Now if we will keep these methods in the interface then every implementing class implement these methods as well and hence there will be no point of Single Responsibility and concern separation.

Sagar Kharab
  • 369
  • 2
  • 18