0

I was recently pointed to this question (What does it mean to "program to an interface"?) and wanted to get some clarification.

LinkedList<Integer> test1 = new LinkedList<Integer>(); 
List<Integer> test2 = new LinkedList<Integer>(); 

From what I've read, the first LinkedList/List determines what methods can be used. So for test1, you can do test1.peek() while you can't for test2. Is that because, for test2, that you are creating a LinkedList but going to be implementing the methods of the List interface? In other words, for test2, you've created a LinkedList with a prev & next node but are choosing to implement the methods outlined in the List interface?

Guess I'm a bit confused because I thought LinkedList is a class that implements the List interface, but for test2, we're creating a LinkedList and implementing a List again?

Felix
  • 13
  • 3
  • I am not quite sure I understand your question correctly. Is it about what methods are accessible on `test2`? If so, it is really the same concept as it is with inheritance: the static type of the variable defines what methods can be accesed. Thus, for `test2` one can only call methods defined in `List`. – Turing85 Aug 12 '20 at 21:14
  • Both lines create a full `LinkedList`, nothing is missing. You have to differentiate variables from instances. In your code 2 `LinkedList` instances are created and `2` variables are created. `test1` is a variable that is allowed to refer to `LinkedList` instances. `test2` is a variable allowed to refer to `List` instances. As a `LinkedList` **is** a `List` as well, the variable is allowed to point to that as well. Think about `Animal animal = new Dog();`, its the same with inheritance. – Zabuzard Aug 12 '20 at 21:15
  • When coding to the interface, you are using the methods that are present on the interface (a la ```test2```). When you use the concrete class (```test1```), you are able to use the methods of both the interface (```List```) and the concrete class (```LinkedList```). You can use ```test2``` like a ```LinkedList``` by casting, but of course it could break if ```test2``` is instantiated with another type (e.g. ```ArrayList```) – Gryphon Aug 12 '20 at 21:25

3 Answers3

1

LinkedList implements List; List does not implement LinkedList.

peek is a method of a LinkedList, but is not a method of List.

Because of this situation, test2.peek() is a compile time error.

Specifically, test2 only exposes the functionality of a List.

DwB
  • 37,124
  • 11
  • 56
  • 82
  • 1
    "*LinkedList is a superset of List*" - It is the other way around: Every `LinkedList` is a `List`, but not every `List` is a `LinkedList`. Thus `List` is the superset of `LinkedList`. – Turing85 Aug 12 '20 at 21:26
  • 3
    The set of methods of `LinkedList` is a superset of the set of methods of `List`. The set of `List`s is a superset of the set of `LinkedList`s. – Louis Wasserman Aug 12 '20 at 21:27
1

From what I've read, the first LinkedList/List determines what methods can be used.

Yes, the "first LinkedList/List" is the type of the reference you are declaring. You can invoke the methods exposed by a reference's type on that reference, including inherited ones, and no others.

So for test1, you can do test1.peek() while you can't for test2.

Yes.

Is that because, for test2, that you are creating a LinkedList but going to be implementing the methods of the List interface?

No. You are not implementing anything there. You are initializing references test1 and test2 to refer to objects of class LinkedList, which is a concrete class that implements List, and therefore provides concrete implementations of all methods defined by the List interface. LinkedList also provides implementations of some methods defined by other interfaces and by superclasses, and, in principle, it could define and implement some methods unique to it.

In other words, for test2, you've created a LinkedList with a prev & next node but are choosing to implement the methods outlined in the List interface?

Again, you are not implementing any methods here. By choosing to access a LinkedList<Integer> object via a reference of type List<Integer>, you ensure that only those LinkedList methods that are defined by List can be invoked via that reference. That doesn't change the nature of the object itself. There will be other references to it at least sometimes, some of them of type LinkedList<Integer>. Those can be used to invoke methods exposed by LinkedList but not by List on the object.

Guess I'm a bit confused because I thought LinkedList is a class that implements the List interface,

Yes.

but for test2, we're creating a LinkedList and implementing a List again?

Every LinkedList is a List. This is one of the main consequences of the fact that former class implements the latter interface. By accessing an object of class LinkedList via a reference of type List, you limit yourself to using only those parts of it that are defined by List, but you have not changed the object itself in any way. It is still a LinkedList.

Consider human roles. I'm a son, a brother, a father, an employee, a friend, and many other things, but most people in my life interact with me according to only one or two of those roles. For example, my boss regularly asks me, her employee, to do various pieces of work for her, but she would never ask me to give her a weekly allowance as if I were her father.

Types, and in particular interface types, can be regarded like those roles. If you need an employee, it doesn't have to be someone exactly like me -- it can be anyone who can fill the "employee" role. And operating in that role does not make anyone not have all their other roles.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

In addition to the other correct answers, I'd like to point out what the compiler ensures:

LinkedList<Integer> test1 = new LinkedList<Integer>(); 

Here the compiler will make sure that anyting assigned to test1 fulfills the LinkedList interface.

List<Integer> test2 = new LinkedList<Integer>(); 

Here the compiler will make sure that anyting assigned to test2 fulfills the List interface 'only'.

While that means you cannot call methods of the LinkedList interface on test2, it gives the flexibility to assign any implementation of List to it without changing any user of it.

That said: if you do not need specific types (interfaces), you should use a more common type instead to stay more flexible. So if you only want to know the size and iterate the elements, you could use Collection - but this will not allow to access the 3rd element easily.