This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why should the interface for a Java class be prefered?
In Java, is there a difference between these two lines? If so, what is it, and when should I use either one? Is there a preferred convention?
Note that ArrayList implements List.
List<String> bunchOfStrings = new ArrayList<String>();
ArrayList<String> bunchOfStrings = new ArrayList<String>();
In Java, is there a difference between these two lines?
Yes, there is a slight difference, and the List<String> variant is preferred.
Is there a preferred convention?
The convention says that you should "program against interfaces". The reason is that it becomes much easier to swap the actual implementation (in this case from ArrayList to say LinkedList).
In both case you are instantiating an ArrayList. The difference is that in the first case you are referring it as a List (the interface that ArrayList implements ), so you don't have access to specific method of ArrayList class, but only interfaces method.
use thi first:
List<String> bunchOfStrings = new ArrayList<String>();
This way you can switch different List implementation (ArrayList, Vector):
public class AClass(){
List<String> bunchOfStrings;
public List<String> getList(){
bunchOfStrings = new ArrayList<String>();
//or you can switch to : bunchOfStrings = new Vector<String>();
return bunchOfString;
}
}
You should use the most generic type possible. So in this case that's List. The only time you would use a more specific type is if that type had methods defined on it that the more generic type does not.
The reason is that if a method accepts a type, like List, the user of the method can provide any type of List they want. If a method only accepts an ArrayList, the user can't use any other type of List.
If you declare bunchOfStrings as a List, you can't call any of the ArrayList methods (without casting), even though it is pointing to an ArrayList object -- you can only call methods that are declared in the List class.
For this reason, you might think that it's better to always declare your variable type to be as specific as possible, but declaring it as a List is generally preferable because it allows you to change the underlying implementation of your List without having to change anything else in your code. You can easily modify your code as follows without breaking anything else in your code:
List<String> bunchOfStrings = new LinkedList<String>();
As a rule of thumb, only ever declare the type of your variable to be a specific subclass if you...
...need access to methods that are only available in the subclass.
...need to pass the object instance to a method that only accepts objects of that subclass.
This is called Polymorphism. It is very useful and has no real drawbacks.
Pros:
You can send this instance variable to any method that wants a "List" object.
Using List in a method declaration, you are opening up the method to anything that is a sub-type of List, instead of just of type ArrayList.
Cons:
You would have to cast your variable to an ArrayList to access or set any features/methods/fields that are in ArrayList (but not in List). But those things are still available.
Related
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.
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).
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.
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.
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.
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>();
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.
Say I extend a Java class like java.util.List to create a custom class called MyList... Is there any way if my peers write code using List, I can convert it into MyList during compilation/runtime?
i.e. If they have something like:
List groceryList = new List();
it should be compiled/run like:
MyList groceryList = new MyList();
I know annotations can do something of this sort. Is it possible to use them in this case? If yes, how?
This is known as downcasting.
The short answer is that if they created the object with the new command, such as in your example, then no, you will not be able to cast it.
What you can do, is define a constructor in MyList class that accepts the object-to-be-converted as a parameter and uses it to create a new object. The list is a bit special because you can create new lists from existing ones . For example:
public MyList (List oldList)
{
super(oldList); //this will copy the objects of the list to your custom list
//But you could do any other operations to create the new object from the parameter(s)
...
}
and use it as
MyList groceryList = new MyList(oldList);
While upcasting in java is mostly safe, Downcasting in Java is not something you should frequently use, unless really needed, since the subclass may not support some attributes or methods that the superclass can.
List<String> c = new ArrayList<String>();
I don't understand why they did this,i mean they could have used,
List<String> c=new List<String>();
OR
ArrayList<String> c=new List<String>();
What is the use of this type of syntax and how to use it...
It is actually good that we have a List interface. That way we have the option of using the different type of lists (ArrayList, linkedlist, etc) and inherit the common methods among them.
For example, every list needs to have an add and remove method. But depending on the list, the implementation will vary. An ArrayList will add an item differently than a LinkedList.
So the List interface helps Java coders abstract the common details between lists that will later on have different implementations.
I hope this helps.
You could look at it this way. The interface List provides the common methods every list implementation has, whereas a concrete type like ArrayList provides a specific behaviour on how the list functions.
So List<String> c = new ArrayList<String>(); means a general List of Strings, which has methods like add(), clear() and get() but which acts like an ArrayList.
With using an interface like this you could switch the behaviour of that list at runtime. That means you could do something like this:
List<String> list = new ArrayList<String>();
list = new LinkedList<String>();
That is not possible if you declared list as ArrayList from the beginning.
ArrayList<String> list = new ArrayList<String>();
list = new LinkedList<String>();
This will generate a compiler-error Type mismatch: cannot convert from LinkedList<String> to ArrayList<String>.
To be more technical, interfaces define sort of a "contract", which means that every class implementing that interface has to provide its defined methods. So if you use an interface, you can be sure that any created object implementing it has the same common methods, since they have to submit to the "contract". But how that object behaves and how the provided methods are implemented is completely up to you.
I am a bit confused about instance creating since I started to learn Generics because I realize for example, you can create a HashMap like this,
HashMap hashmap = new HashMap();
but also,
HashMap<String,String> hashmap = new HashMap<String, String>();
While I can also declare instance hashmap like this since HashMap is implemented from Map Interface
Map<String,String> hashmap = new HashMap<String, String>();
But if above is true, then I can also create instance of ArrayList this way, is it right?
List<String> arraylist = new ArrayList<String>();
And, how about a custom defined one, lets say class Walk implemented from interface Move so to create an instance object of Walk I can use code like both,
Walk walk = new Walk();
Move walk = new Walk();
And these won't cause problems, are these two declarations the same? And is Implementation the key feature to enable the feature while how about class extended from another for exapmle, class Son extended from class Father, is this one legal then?
Father son = new Son();
Okay, so that's a lot of questions and stuff to talk about but I'll see how much I can cover in a short answer.
Generics in Collection Declarations.
Let's start with reasons to use generics in your declarations rather than not using them.
Take the following two declarations;
HashMap hashmap = new HashMap();
HashMap<String,String> hashmap = new HashMap<String, String>();
The first will accept any key/value combinations and you will have to manually use instanceof and casting to get the objects from the map because there is no guarantee that it will contain the object types you think it does.
The second uses generics in the declaration and ENSURES that only String keys and values will make their way into your HashMap instance at compile time. Also, when you call get(), you will have a String object returned automatically and will not have to check and cast it yourself. Unless you have a very good reason, you should always be using generics with your declarations.
Polymorphism in Collection Declarations.
Now onto polymorphism when declaring your collections. Take the following two examples;
List<String> sl = new ArrayList<String>();
ArrayList<String> sl2 = new ArrayList<String>();
The first is more flexible and could hold any custom List subclass that any method decides to return. This means that methods such as get() might return slightly different results depending on the List subclass it contains, or that the items in the List might be kept in a different order or such. Think about that for a moment. This gives you much greater flexibility but much fewer certainties.
If you absolutely want to make sure that your List is an ArrayList and so that variable's methods will always act in accordance to ArrayList (and will always use insertion order), then use the second example. Otherwise if you want to allow some flexibility in List type (for example if you want it to be able to take some ordered AND sorted lists) use the first.
I hope this helps, and I hope I didn't miss anything too important.
Here are some links for further reading from the official Java tutorials;
Official Generics tutorials.
Official Inheritance & Polymorphism tutorials.
What is a raw type and why shouldn't we use it?
Your first line, HashMap hashmap = new HashMap() works because you're using raw types. This will throw a compiler warning in more recent versions of Java, but it's perfectly valid syntax; it essentially means that you can store keys and values of any type, and you won't get a compiler error. (This answer discusses raw types in more detail).
The only difference between that and your second instantiation of HashMap is that you are providing some restrictions on what the types of your keys and values can be.
All the rest of your examples are related to inheritance. As long as the left-hand side of an object instantiation is more general than the right-hand side (i.e., the type of the right-hand side inherits from the type of the left-hand side), then there's no compiler error.
Part of your confusion seems to be about the difference between implementing an interface and extending a class. For this problem, there isn't a difference; you can instantiate either the same way.
Legal ways to create an instance of set/map/list with generics: (E is an object of some class)
List<E> arraylist = new ArrayList<E>();
Map<Integer,E> hashmap = new HashMap<Integer, E>();
LinkedList<E> list = new LinkedList<E>();
Generics can be defined using
Data types(Integer, Double, etc)
Reference variables
Array of reference variable,
List, Queue or even Map
With the help of generics, its easier because you wont have to type cast from Object type to the required type everywhere else in the program. Such as consider the program below:
(Legal ways to create an instance of set/map/list without generics)
public class ListDemo {
public static void main(String[] args) {
ArrayList courseList = new ArrayList();
courseList.add("Java");
courseList.add("J2EE");
courseList.add("Android");
courseList.add("Hibernate");
courseList.add("Spring");
System.out.println("Displaying the contents: ");
for (Object obj : courseList)
{
String courseName = (String)obj;
System.out.println(courseName);
}
}
}
If you observe, type casting to String from Object is needed. Therefore when same kind of data is to be stored in a list, its better to go for Generics.
Whereas consider the program below, where different kinds of data is to be stored onto a list. Then, the default Object type comes into use.
public class ListDemo {
public static void main(String[] args) {
ArrayList sampleList = new ArrayList();
sampleList.add("StackOverflow");
sampleList.add(12345);
sampleList.add(new Car (2014,"Hyundai","SantaFe"));
sampleList.add(23.234);
System.out.println("Displaying the contents: ");
for (Object obj : sampleList)
System.out.println(obj);
}
}
Also note that compiler gives a Type Safety warning "The method add(Object) belongs to the raw type ArrayList. References to generic type ArrayList should be parameterized"
Read more on Generics here.
This has nothing to with generics, it's all inheritance: A a = new B() is valid when:
B is A (e.g., A a = new A())
A is an ancestor of B (as in Father above)
B or one of its ancestors implement interface A (as in Map and List above)
This is true whether or not generics are used.
But if above is true, then I can also create instance of ArrayList this way, is it right?
Yes, and it's better because it hides the detail that it's an ArrayList.
And, how about a custom defined one, lets say class Walk implemented from interface Move so to create an instance object of Walk I can use code like both,
These aren't generic; they're just a typical class hierarchy. Generics are used for things like collections that you want to use for a specific data type.
And these won't cause problems, are these two declarations the same?
Nearly, only you're only exposing Move's methods with the second declaration. It's saying "here's a movement, but you don't need to know the details about which movement it is."
And is Implementation the key feature to enable the feature while how about class extended from another for exapmle,
Search around for Abstract Class vs. Interface. Part of it is the "is a" vs "can it" distinction, and part is that class inheritance lets you provide an implementation. The quick aside in the guy who created Java jokingly said he regretted adding inheritance, saying he favored interfaces and composition.
If you want a good example of classes vs. interfaces, look at Collection, List, and AbstractList. They're structured quite well, and you'll notice you rarely knowingly work with an AbstractList unless you're subclassing it.
class Son extended from class Father, is this one legal then?
Could be. If Father has the getChildren() method and Son has getFather() and getMother().
I'm learning that it is generally better to make the declared type as general as possible, but I'm not sure why. For example, in most cases, this...
List<String> myList = new ArrayList<String>();
is considered better than this:
ArrayList<String> myList = new ArrayList<String>();
One of the reasons given for this preference is quoted below( Java - declaring from Interface type instead of Class)
Yes, you are correct. You should declare as the most general type providing the methods you >use.This is the concept of polymorphism.
However, polymorphism usually increases the amount of methods available to you because you can also access the methods of your super-types. But, in the case of declaring with interface types you actually restrict the number of methods available to you because you can only access methods in the interface, and you cannot access those just belonging to the class type.
So is this really Polymorphism? and why is it considered "more general" when it seems more restrictive, if anything, to me? What am I missing?
List<String> myList = new ArrayList<String>();
is generally preferred over
ArrayList<String> myList = new ArrayList<String>();
because usually you do not need methods that are specific to ArrayList. Usually, the methods defined in List are more than enough to satisfy typical needs. This allows you to change the implementation without changing the rest of the code, like this:
List<String> myList = new LinkedList<String>();
and nothing else changes.
Only use the specific type for the variable if you need the methods that are specific to that type. Only use ArrayList for your variable if you really do need ArrayList-specific methods.
Say you have a method like this:
public void doSomething(ArrayList<String> items) {
// do something with the list
}
How do you call this method?
ArrayList<String> list1 = new ArrayList<String>();
doSomething(list1); // good
LinkedList<String> list2 = new LinkedList<String>();
doSomething(list2); // bad
// you'd have to make a new array list and add all the items from your linked list to it
doSomething(new ArrayList<String>(list2));
Both list1 and list2 are List's but because you made your method signature requires ArrayList you cannot pass in LinkedList, or better yet List. That is why you code to an interface - it allows you to write one method that supports any implementation of List.
If you want to make it even better, use Collection instead of list, it will support Set's as well then.
As far as "increases the amount of methods available" - what method would you call on ArrayList that is not available on List? One of the benefits of interfaces is that they hide implementation complexities from you and allows you to use difference classes via a well defined interface that hides the details of the underlying implementation.
Wikipedia defines Polymorphism as follows:
In programming languages and type theory, polymorphism (from Greek πολύς, polys, "many, much" and μορφή, morphē, "form, shape") is the provision of a single interface to entities of different types.
Polymorphism enables writing algorithms that can work on more than one type, therefore increasing code reuse.
For instance, if we have a method
void sort(ArrayList<String> list);
that method can only be used for sorting an ArrayList<String>. That's not very useful. But if you have
<T> void sort(ArrayList<T> list);
the method can be applied to far more types, and is therefore more useful. But it can still only sort ArrayLists. Taking the idea farther, we have
<T> void sort(List<T> list);
which can sort any kind of list, whatever its provenance or internal representation.
Generally, your methods should require as little as possible of their arguments, to be useful in as many circumstances as possible.