Reputation: 87
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?
Upvotes: 3
Views: 5894
Reputation: 109613
Many answers already, but let us be explicit.
First
List<String> list = new LinkedList<String>();
can be written using the diamond operator <>
to shorten the text.
List<String> list = new LinkedList<>();
list
as the more general interface List
?If you only need List
methods (isEmpty
, add
), then you got stronger code. You can later change the implementation to ArrayList
instead of LinkedList
. All usages cannot merely handle LinkedList
but any List. This is called programming against interfaces
.
(The answer:) And if you want to use LinkedList functionality:
LinkedList<String> list = new LinkedList<>();
list.addLast("string");
list.removeLast();
If list
would be a List
it could not call things like addFirst
and removeFirst
which do not exist in List
.
Upvotes: 0
Reputation: 13
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.
Upvotes: 0
Reputation: 262842
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 inArrayList
but not inList
.
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 inLinkedList
?
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.
Upvotes: 7
Reputation: 369
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.
Upvotes: 0
Reputation: 1028
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.
Upvotes: 0
Reputation: 487
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
Upvotes: 1