可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have heard several times that when instantiating objects you should do:
"Interface" name = new "Class"();
For example for the class linkedlist that implements List
:
List<String> name = new LinkedList<String>();
LinkedList
implements many interfaces, including queue, deque, etc. What is the difference between the above code and
LinkedList<String> name = new LinkedList<String>();
or
Queue<String> name = new LinkedList<String>();
Why must the type be specified twice as well; it seems redundant but oracledocs don't seem to mention it.
回答1:
LinkedList<String> name = new LinkedList<String>();
is redundant in Java 7. It can be rewritten to LinkedList<String> name = new LinkedList<>();
.
The reason you want to write something similar to:
// Java 7 way:
List<String> name = new LinkedList<>();
is to provide you with the freedom of changing your data collection later, if you change your mind. Your code is much more flexible this way. What you should note about this, is that the methods you are able to use are limited to the left-hand side type (List
in this case). This means that you may not get all the functionality you want, if you use a type that is higher in the hierarchy (Object
being the extreme example).
回答2:
LinkedList<String> name = new LinkedList<>();
Will expose the methods that are defined in LinkedList
and its superclasses.
Queue<String> name = new LinkedList<>();
Will expose the methods that are defined in Queue
and the interfaces it extends.
You should define the object as a class/interface that holds everything (methods, variables, etc) that you need, while also making it as abstract as possible.
This hides implementation details and allows for easier switching between implementation, for example.
Note that you don't have to specify the type in the initialization due to the diamond operator.
回答3:
Firstly, an Interface is a abstract type that is used to specify what a classes must implement. Any class the implements an interface must satisfy its contract by implementing its method and is of that type.Therefore, by implementing the List interface LinkList is a type of list.
By coding to the interface and not to the concrete class your code becomes more loosely coupled. This means that your code is not bound to the LinkList but rather the List interface and can be changed to anything that implements the list interface at anytime. Therefore, if for some reason the LinkList no longer meets you requirements and you need, lets say a ArrayList instead since it also implements the List interface you can just change to :
List<String> name = new ArrayList<String>();
And all your other programming logic would remain the same,since both classes have the same methods because they implement the same interface.
回答4:
This isn't as simple as it looks. If you use:
List<Foo> name = new LinkedList<Foo>();
if you ever wanted to switch from linked lists to arraylists it would be less maintenance.
About the redundancy, List name = new LinkedList()
declares name
of type List
and invokes the LinkedList
constructor. You could have as follows:
List<Foo> name = someRandomObject.someRandomHelperMethod();
This helper method "just happens" to return a list, so there is no redundancy.
With Java 7 the apparently-redundant generic args can be skipped:
List<Foo> someL = new ArrayList<>();
as opposed to
List<Foo> someL = new ArrayList<Foo>();
回答5:
If you code to interfaces you can easily switch implementations easily. If an ArrayList suits your needs better than a LinkedList then you can change one line only. If you need a particular method that is in the LinkedList class (or any other of the sub types) then it is perfectly valid to have
LinkedList<String> name = new LinkedList<String>()
As for the redundancy if you are referring to the generic type declaration then I would recommend you look at the Guava libraries. These have some nice static import methods to remove this. For example for an ArrayList it would be
List<String> name = newArrayList()
instead of
List<String> name = new ArrayList<String>()
There is a similar method for LinkedList too.
In Java 7 there is also the diamond operators but this is still a bit more verbose than the static import from Guava.
回答6:
What is the difference between the above code and
LinkedList<String> name = new LinkedList<String>();
or
Queue<String> name = new LinkedList<String>();
There are a few key differences.
The difference between using the List
interface and using a LinkedList
object is that I'm defining my interaction with the implementing object to adhere to the List
interface. Ultimately, I don't care what the implementation is*, so long as it behaves like a List
of some kind.
If I use the concrete LinkedList
object, then I not only have to care what the type is, but I can use more things than I probably should - since it implements the Queue
interface too, I can do queue-like operations on it, which may or may not be appropriate.
Ultimately, your code should be SOLID; here, we adhere to the dependency inversion principle, which allows us to depend on the interface as opposed to the concrete implementation. It allows us to subsitute the LinkedList
for an ArrayList
should we want to.
*: Of course you should care what the underlying implementation is, for performance reasons. But, you may not care yet.