Related
List<T> is an interface and can not normally be instantiated, however you can create List of a fixed length through little hacks like Arrays.asList. Methods which return List<T> also seem to instantiate a List.
Given that List is an interface, what exactly does the JVM do to create it?
Interface can't be instantiated. If you see the code behind asList method its using arrayList. Its like:
#SafeVarargs
#SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
However if you want to take advantage of runtime polymorphism, you could do something like:
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
See that i used interface on left hand side and i can use either array backed array list implementation or a linked list based on my business scenario given advantage of one over the other.
Can someone explained, as detailed as possible, the differences between the following types?
List
List<Object>
List<?>
Let me make this more specific. When would I want to use
// 1
public void CanYouGiveMeAnAnswer(List l) { }
// 2
public void CanYouGiveMeAnAnswer(List<Object> l) { }
// 3
public void CanYouGiveMeAnAnswer(List<?> l) { }
As the other posts have noted, you are asking about a Java feature called generics. In C++, this is called templates. This feature in Java is usually easier to work with than the that found in C++.
Let me answer your questions functionally (if that's not a naughty word for OO discussions).
Before generics, there were concrete classes like Vector.
Vector V = new Vector();
Vectors hold any object you give them.
V.add("This is an element");
V.add(new Integer(2));
v.add(new Hashtable());
They do this by casting all values given to it into an Object (the root of all Java classes). When you attempt to retrieve the values stored in your Vector, you need to cast the value back into the original class (if you want to do anything meaningful with it).
String s = (String) v.get(0);
Integer i = (Integer) v.get(1);
Hashtable h = (Hashtable) v.get(2);
Casting gets old fast. More than that, the compiler complains to you about unchecked casts. The most urgent problem with casting like this is that consumers of your Vector have to know the classes of its values at compile time in order to cast correctly. In cases where the producer of the Vector and the consumer of the same are completely isolated from each other (think RPC messages), this can be a fatal issue.
Enter generics. Generics attempt to create strongly typed classes to do generic operations.
ArrayList<String> aList = new ArrayList<String>();
aList.add("One");
String element = aList.get(0); // no cast needed
System.out.println("Got one: " + element);
The Design Patterns book encourages the reader to think in terms of contracts, not concrete types. There is wisdom (and code re-use) in divorcing variables from their implementing class.
With this in mind, you might think that all implementations List objects should do the same set of things: add(), get(), size(), etc. With a little reflection, you can imagine many implementations of List operations that obey the List contract in various ways (e.g. ArrayList). However, the type of data these objects deal with is orthogonal to the actions performed on them.
Put it all together and you'll see the following kinds of code frequently:
List<String> L = new ArrayList<String>();
You should read that as "L is a kind of List that deals with String objects". When you start dealing with Factory classes, it is critical to deal with contracts rather than specific implementations. Factories produce objects of various types at runtime.
Using generics is pretty easy (most of the time).
One day you may decide you want to implement your own generic class. Perhaps you want to write a new database abstraction interface that elides the differencesbetween various data stores. When you define that generic class, you will use <t> as a placeholder for the kind of object that will be manipulated by the methods.
If you are still confused, use the generic classes for List until you are comfortable. Later, you can dive into the implementation with a bit more confidence. Or you can look at the source code for the various List classes that ship with the JRE. Open source is great that way.
Have a look at the Oracle/Sun docs about generics.
Cheers.
In my own simple terms:
List
Would declare an ordinary collection, can hold any type, and will always return Object.
List<Object>
Will create a list that can hold any type of object, but can only get assigned a another List<Object>
For instance this doesn't work;
List<Object> l = new ArrayList<String>();
Of course you can add anything but only can pull Object.
List<Object> l = new ArrayList<Object>();
l.add( new Employee() );
l.add( new String() );
Object o = l.get( 0 );
Object o2 = l.get( 1 );
Finally
List<?>
Will let you assign any type, including
List <?> l = new ArrayList();
List <?> l2 = new ArrayList<String>();
This would be called collection of unknown and since the common denominator of unknown is Object you will be able to fetch Objects ( a coincidence )
The importance of unknown comes when its used with subclassing:
List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles
List<? extends Collection> l = new ArrayList<String>(); // doesn't,
// because String is not part of *Collection* inheritance tree.
I hope using Collection as the type doesn't create confusion, that was the only tree that came to my mind.
The difference here, is that l is a collection of unknow that belongs to the Collection hierarchy.
To add to the already good answers here:
Method arguments:
List<? extends Foo>
good choice if you don't intend to alter the list, and only care that everything in the list is assignable to type 'Foo'. This way, the caller can pass in a List<FooSubclass> and your method works. Usually the best choice.
List<Foo>
good choice if you intend to add Foo objects to the list in your method. The caller may not pass in a List<FooSubclass>, as you intend to add a Foo to the List.
List<? super Foo>
good choice if you intend to add Foo objects to the list, and it's not important what else is in the list (ie, you are ok getting a List<Object> that contains a 'Dog' that has nothing to do with Foo).
Method return values
just like method arguments, but with the benefits reversed.
List<? extends Foo>
Guarantees that everything in the returned List has type 'Foo'. It might be List<FooSubclass> though. Caller cannot add to the List. This is your go-to choice and the most common case by far.
List<Foo>
Just like List<? extends Foo> but also allows the caller to add to the List. Less common.
List<? super Foo>
allows the caller to add Foo objects to the List, but does not guarantee what will be returned from list.get(0)... it could be anything from Foo to Object. The only guarantee is that this won't be a list of 'Dog' or some other choice that would prevent list.add(foo) from being legal. Very rare use case.
I hope that helps. Good luck!
ps. To sum up... two questions...
do you need to add to the List? Do you care what is in the list?
yes yes - use List<Foo>.
yes no - use List<? super Foo>.
no yes - use <? extends Foo> --- most common.
no no - use <?>.
I refer you to the excellent Java Generics tutorial, and the "advanced" Generics tutorial, both available from Sun Microsystems. Another great resource is the Java Generics and Collections book.
I will try to answer this in detail. Before generics we were having only List (a raw list) and it can hold almost anything we can think of.
List rawList = new ArrayList();
rawList.add("String Item");
rawList.add(new Car("VW"));
rawList.add(new Runnable() {
#Override
public void run() {
// do some work.
}
});
The major problem with the raw list is when we want to get any element out of such list it can only guarantee that it would be Object and for that reason we need to use casting as:
Object item = rawList.get(0); // we get object without casting.
String sameItem = (String) rawList.get(0); // we can use casting which may fail at runtime.
So conclusion is a List can store Object (almost everything is Object in Java) and always returns an Object.
Generics
Now lets talk about generics. Consider the following example:
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
stringsList.add(new Car("Fiat")); //error
String stringItem = stringsList.get(0);
In the above case we cannot insert anything other than String in stringsList as Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. And we get error when we try to insert a Car instance in it. Also it eliminates cast as you can check when we invoke get method. Check this link for understanding why we should use generics.
List<Object>
If you read about type erasure then you will understand that List<String>, List<Long>, List<Animal> etc. will be having different static types at compile time but will have same dynamic type List at run time.
If we have List<Object> then it can store only Object in it and almost everything is Object in Java. So we can have:
List<Object> objectList = new ArrayList<Object>();
objectList.add("String Item");
objectList.add(new Car("VW"));
objectList.add(new Runnable() {
#Override
public void run() {
}
});
Object item = objectList.get(0); // we get object without casting as list contains Object
String sameItem = (String) objectList.get(0); // we can use casting which may fail at runtime.
It seems List<Object> and List are same but actually they are not. Consider the following case:
List<String> tempStringList = new ArrayList<>();
rawList = tempStringList; // Ok as we can assign any list to raw list.
objectList = tempStringList; // error as List<String> is not subtype of List<Obejct> becuase generics are not convariant.
You can see we can assign any list to raw list and major reason for that is to allow backward compatibility. Also List<String> will be converted to List at run time due to type erasure and assignment will be fine anyways.
But List<Object> means it can only refer to a list of objects and can also store objects only. Even though String is subtype of Object we cannot assign List<String> to List<Object> as generics are not covariant like arrays. They are invariant. Also check this link for more. Also check the difference between List and List<Object> in this question.
List<?>
Now we are left with List<?> which basically means list of unknown type and can refer to any list.
List<?> crazyList = new ArrayList<String>();
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
crazyList = stringsList; // fine
The character ? is known as wildcard and List<?> is a list of unbounded wildcard. There are certain points to observe now.
We cannot instantiate this list as the following code will not compile:
List<?> crazyList = new ArrayList<?>(); // any list.
We can say a wildcard parameterized type is more like an interface type as we can use it to refer to an object of compatible type but not for itself.
List<?> crazyList2 = new ArrayList<String>();
We cannot insert any item to it as we don't know what actually the type would be.
crazyList2.add("Apple"); // error as you dont actually know what is that type.
Now question arises When would I want to use List<?>?
You can think of this as a read-only list where you don't care about the type of the items. You can use it to invoke methods like returning the length of the list, printing it etc.
public static void print(List<?> list){
System.out.println(list);
}
You can also check the difference between List, List<?>, List<T>, List<E>, and List<Object> here.
Simplest explanation which is not "RTFM":
List
Will generate lots of compiler warnings, but is mostly equivalent to:
List<Object>
While:
List<?>
basically means its something generic, but you don't know what the generic type is. Its great for getting rid of compiler warnings when you cant modify the return types of other things that just returned List. Its much more useful in the form:
List<? extends SomeOtherThing>
The shortest possible explanation is: The second item is a list that can hold any type, and you can add objects to it:
List<Object>
The first item you list is treated as essentially equivalent to this, except you will get compiler warnings because it is a "raw type".
List
The third is a list that can hold any type, but you cannot add anything to it:
List<?>
Basically, you use the second form (List<Object>) when you truly have a list that can contain any object and you want to be able to add elements to the list. You use the third form (List<?>)when you receive the list as a method return value and you will iterate over the list but never add anything to it Never use the first form (List) in new code compiling under Java 5 or later.
I'd put it this way: While List and List<Object> can contain any type of objects, List<?> contains elements of an unknown type, but once that type is captured, it can only contain elements of that type. Which is why it is the only type safe variant of those three, and therefore generally preferable.
To complement the tutorials mentioned by Rob, here's a wikibook explaining the topic:
http://en.wikibooks.org/wiki/Java_Programming/Generics
Edit:
No restrictions on type of items in list
Items in list must extend Object
Wildcard used by itself, so it matches anything
Would it be naive of me to conclude at this point that there's hardly any/no difference at all?
When would I want to use
public void CanYouGiveMeAnAnswer( List l ){}
When you cant to do all the casting your self.
When would I want to use
public void CanYouGiveMeAnAnswer( List l<Object> ){}
When you want to restrict the type of the List. For instance, this would be an invalid argument.
new ArrayList<String>();
When would I want to use
public void CanYouGiveMeAnAnswer( List l<?> ){}
Mostly never.
List, List<?>, and List<? extends Object> are the same thing. The second is more explicit. For a list of this type, you cannot know what types are legal to put into it, and you don't know anything about the types you can get out of it, except that they will be objects.
List<Object> specifically means that the list contains any sort of object.
Let's say we make a list of Foo:
List<Foo> foos= new ArrayList<Foo>();
It is not legal to put a Bar into foos.
foos.add(new Bar()); // NOT OK!
It is always legal to put anything into a List<Object>.
List<Object> objs = new ArrayList<Object>();
objs.add(new Foo());
objs.add(new Bar());
But you mustn't be allowed to put a Bar into a List<Foo> - that's the whole point. So that means that this:
List<Object> objs = foos; // NOT OK!
is not legal.
But it's ok to say that foos is a list of something but we don't know specifically what it is:
List<?> dontKnows = foos;
But that then means that it must be prohibited to go
dontKnows.add(new Foo()); // NOT OK
dontKnows.add(new Bar()); // NOT OK
because the variable dontKnows does't know what types are legal.
List < Object > is meant to pass input type parameter of an Object. While List < ? > represents Wildcard type. The wildcard < ? > is of Unknown parameter type. The wildcard cannot be used as a type argument for a generic method and cannot be used to create a generic instance of a class. Wildcard can be used to extend a subtype class, List < ? extends Number >. To relax the restriction of an Object type and in this case to relax "Number" Object type.
In terms of List functionality differences, the other responses already answered this question. In terms of applicable rules of Java generics, it's a complicated topic. I wrote an in-depth article about Java generics rules, this is the link: https://medium.com/#royalilin/java-generics-rules-1d05de86e9cb
I was wondering if there is a way in Java to do something like
Class c = List<String>.class;
Class c2 = List<Date>.class;
I need something like this to create a map that stores the class name (with generic type) and the corresponding object which I can later lookup. For example,
Map<Class, Object> dataMap = new HashMap<Class, Object>();
dataMap.put(c, listOfStrings);
dataMap.put(c2, listOfDates);
Is this not possible because of type erasure during runtime ?
You can't do it quite like this, but you can achieve your overall aim using the same approach as Guice does with TypeLiteral. If you're using Guice already, I suggest you use that directly - otherwise, you might want to create your own similar class.
Essentially, the idea is that subclasses of a generic type which specify type arguments directly retain that information. So you write something like:
TypeLiteral literal = new TypeLiteral<List<String>>() {};
Then you can use literal.getClass().getGenericSuperclass() and get the type arguments from that. TypeLiteral itself doesn't need to have any interesting code (I don't know whether it does have anything in Guice, for other reasons).
No, it is not possible. You can't even refer to List<String>.class in your code - it results in a compilation error. There is only one single class object for List, and it is called List.class.
Is this not possible because of type erasure during runtime ?
Correct.
Btw this is a generic type, not an annotated type.
Update
On second thought, you can have something fairly close to your Map above, by tweaking Josh Bloch's typesafe heterogenous container (published in Effective Java 2nd Ed., Item 29) a bit:
public class Lists {
private Map<Class<?>, List<?>> lists =
new HashMap<Class<?>, List<?>>();
public <T> void putList(Class<T> type, List<T> list) {
if (type == null)
throw new NullPointerException("Type is null");
lists.put(type, list);
}
public <T> List<T> getList(Class<T> type) {
return (List<T>)lists.get(type);
}
}
The cast in getList is unchecked, giving a warning, but I am afraid we can't avoid that. However, we know that the value stored for class X must be a List<X>, as this is guaranteed by the compiler. So I think the cast is safe (if you play by the rules, that is - i.e. never call putList with a plain nongeneric Class parameter), thus it can be suppressed using #SuppressWarnings("unchecked").
And you can use it like this:
Lists lists = new Lists();
List<Integer> integerList = new ArrayList<Integer>();
List<String> stringList = new ArrayList<String>();
...
lists.putList(Integer.class, integerList);
lists.putList(String.class, stringList);
List<Integer> storedList = lists.getList(Integer.class);
assertTrue(storedList == integerList);
It is not possible as you are trying.
But you could decorate these lists and create a MyListDates and MyListString instead and store them in the hashmap
This does not compile, any suggestion appreciated.
...
List<Object> list = getList();
return (List<Customer>) list;
Compiler says: cannot cast List<Object> to List<Customer>
you can always cast any object to any type by up-casting it to Object first. in your case:
(List<Customer>)(Object)list;
you must be sure that at runtime the list contains nothing but Customer objects.
Critics say that such casting indicates something wrong with your code; you should be able to tweak your type declarations to avoid it. But Java generics is too complicated, and it is not perfect. Sometimes you just don't know if there is a pretty solution to satisfy the compiler, even though you know very well the runtime types and you know what you are trying to do is safe. In that case, just do the crude casting as needed, so you can leave work for home.
Depending on your other code the best answer may vary.
Try:
List<? extends Object> list = getList();
return (List<Customer>) list;
or
List list = getList();
return (List<Customer>) list;
But have in mind it is not recommended to do such unchecked casts.
With Java 8 Streams:
Sometimes brute force casting is fine:
List<MyClass> mythings = (List<MyClass>) (Object) objects
But here's a more versatile solution:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
There's a ton of benefits, but one is that you can cast your list more elegantly if you can't be sure what it contains:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
That's because although a Customer is an Object, a List of Customers is not a List of Objects. If it was, then you could put any object in a list of Customers.
You can use a double cast.
return (List<Customer>) (List) getList();
Another approach would be using a java 8 stream.
List<Customer> customer = myObjects.stream()
.filter(Customer.class::isInstance)
.map(Customer.class::cast)
.collect(toList());
Note that I am no java programmer, but in .NET and C#, this feature is called contravariance or covariance. I haven't delved into those things yet, since they are new in .NET 4.0, which I'm not using since it's only beta, so I don't know which of the two terms describe your problem, but let me describe the technical issue with this.
Let's assume you were allowed to cast. Note, I say cast, since that's what you said, but there are two operations that could be possible, casting and converting.
Converting would mean that you get a new list object, but you say casting, which means you want to temporarily treat one object as another type.
Here's the problem with that.
What would happen if the following was allowed (note, I'm assuming that before the cast, the list of objects actually only contain Customer objects, otherwise the cast wouldn't work even in this hypothetical version of java):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
In this case, this would attempt to treat an object, that isn't a customer, as a customer, and you would get a runtime error at one point, either form inside the list, or from the assignment.
Generics, however, is supposed to give you type-safe data types, like collections, and since they like to throw the word 'guaranteed' around, this sort of cast, with the problems that follow, is not allowed.
In .NET 4.0 (I know, your question was about java), this will be allowed in some very specific cases, where the compiler can guarantee that the operations you do are safe, but in the general sense, this type of cast will not be allowed. The same holds for java, although I'm unsure about any plans to introduce co- and contravariance to the java language.
Hopefully, someone with better java knowledge than me can tell you the specifics for the java future or implementation.
You should just iterate over the list and cast all Objects one by one
You can do something like this
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
Or the Java 8 way
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
You can't because List<Object> and List<Customer> are not in the same inheritance tree.
You could add a new constructor to your List<Customer> class that takes a List<Object> and then iterate through the list casting each Object to a Customer and adding it to your collection. Be aware that an invalid cast exception can occur if the caller's List<Object> contains something that isn't a Customer.
The point of generic lists is to constrain them to certain types. You're trying to take a list that can have anything in it (Orders, Products, etc.) and squeeze it into a list that can only take Customers.
As others have pointed out, you cannot savely cast them, since a List<Object> isn't a List<Customer>. What you could do, is to define a view on the list that does in-place type checking. Using Google Collections that would be:
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
You can create a new List and add the elements to it:
For example:
List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);
Your best bet is to create a new List<Customer>, iterate through the List<Object>, add each item to the new list, and return that.
Similar with Bozho above. You can do some workaround here (although i myself don't like it) through this method :
public <T> List<T> convert(List list, T t){
return list;
}
Yes. It will cast your list into your demanded generic type.
In the given case above, you can do some code like this :
List<Object> list = getList();
return convert(list, new Customer());
Depending on what you want to do with the list, you may not even need to cast it to a List<Customer>. If you only want to add Customer objects to the list, you could declare it as follows:
...
List<Object> list = getList();
return (List<? super Customer>) list;
This is legal (well, not just legal, but correct - the list is of "some supertype to Customer"), and if you're going to be passing it into a method that will merely be adding objects to the list then the above generic bounds are sufficient for this.
On the other hand, if you want to retrieve objects from the list and have them strongly typed as Customers - then you're out of luck, and rightly so. Because the list is a List<Object> there's no guarantee that the contents are customers, so you'll have to provide your own casting on retrieval. (Or be really, absolutely, doubly sure that the list will only contain Customers and use a double-cast from one of the other answers, but do realise that you're completely circumventing the compile-time type-safety you get from generics in this case).
Broadly speaking it's always good to consider the broadest possible generic bounds that would be acceptable when writing a method, doubly so if it's going to be used as a library method. If you're only going to read from a list, use List<? extends T> instead of List<T>, for example - this gives your callers much more scope in the arguments they can pass in and means they are less likely to run into avoidable issues similar to the one you're having here.
SIMPLEST SOLUTION IS TO USE
(((List<Object>)(List<?>) yourCustomClassList))
List<Object[]> testNovedads = crudService.createNativeQuery(
"SELECT ID_NOVEDAD_PK, OBSERVACIONES, ID_SOLICITUD_PAGO_FK FROM DBSEGUIMIENTO.SC_NOVEDADES WHERE ID_NOVEDAD_PK < 2000");
Convertir<TestNovedad> convertir = new Convertir<TestNovedad>();
Collection<TestNovedad> novedads = convertir.toList(testNovedads, TestNovedad.class);
for (TestNovedad testNovedad : novedads) {
System.out.println(testNovedad.toString());
}
public Collection<T> toList(List<Object[]> objects, Class<T> type) {
Gson gson = new Gson();
JSONObject jsonObject = new JSONObject();
Collection<T> collection = new ArrayList<>();
Field[] fields = TestNovedad.class.getDeclaredFields();
for (Object[] object : objects) {
int pos = 0;
for (Field field : fields) {
jsonObject.put(field.getName(), object[pos++]);
}
collection.add(gson.fromJson(jsonObject.toString(), type));
}
return collection;
}
Can someone explained, as detailed as possible, the differences between the following types?
List
List<Object>
List<?>
Let me make this more specific. When would I want to use
// 1
public void CanYouGiveMeAnAnswer(List l) { }
// 2
public void CanYouGiveMeAnAnswer(List<Object> l) { }
// 3
public void CanYouGiveMeAnAnswer(List<?> l) { }
As the other posts have noted, you are asking about a Java feature called generics. In C++, this is called templates. This feature in Java is usually easier to work with than the that found in C++.
Let me answer your questions functionally (if that's not a naughty word for OO discussions).
Before generics, there were concrete classes like Vector.
Vector V = new Vector();
Vectors hold any object you give them.
V.add("This is an element");
V.add(new Integer(2));
v.add(new Hashtable());
They do this by casting all values given to it into an Object (the root of all Java classes). When you attempt to retrieve the values stored in your Vector, you need to cast the value back into the original class (if you want to do anything meaningful with it).
String s = (String) v.get(0);
Integer i = (Integer) v.get(1);
Hashtable h = (Hashtable) v.get(2);
Casting gets old fast. More than that, the compiler complains to you about unchecked casts. The most urgent problem with casting like this is that consumers of your Vector have to know the classes of its values at compile time in order to cast correctly. In cases where the producer of the Vector and the consumer of the same are completely isolated from each other (think RPC messages), this can be a fatal issue.
Enter generics. Generics attempt to create strongly typed classes to do generic operations.
ArrayList<String> aList = new ArrayList<String>();
aList.add("One");
String element = aList.get(0); // no cast needed
System.out.println("Got one: " + element);
The Design Patterns book encourages the reader to think in terms of contracts, not concrete types. There is wisdom (and code re-use) in divorcing variables from their implementing class.
With this in mind, you might think that all implementations List objects should do the same set of things: add(), get(), size(), etc. With a little reflection, you can imagine many implementations of List operations that obey the List contract in various ways (e.g. ArrayList). However, the type of data these objects deal with is orthogonal to the actions performed on them.
Put it all together and you'll see the following kinds of code frequently:
List<String> L = new ArrayList<String>();
You should read that as "L is a kind of List that deals with String objects". When you start dealing with Factory classes, it is critical to deal with contracts rather than specific implementations. Factories produce objects of various types at runtime.
Using generics is pretty easy (most of the time).
One day you may decide you want to implement your own generic class. Perhaps you want to write a new database abstraction interface that elides the differencesbetween various data stores. When you define that generic class, you will use <t> as a placeholder for the kind of object that will be manipulated by the methods.
If you are still confused, use the generic classes for List until you are comfortable. Later, you can dive into the implementation with a bit more confidence. Or you can look at the source code for the various List classes that ship with the JRE. Open source is great that way.
Have a look at the Oracle/Sun docs about generics.
Cheers.
In my own simple terms:
List
Would declare an ordinary collection, can hold any type, and will always return Object.
List<Object>
Will create a list that can hold any type of object, but can only get assigned a another List<Object>
For instance this doesn't work;
List<Object> l = new ArrayList<String>();
Of course you can add anything but only can pull Object.
List<Object> l = new ArrayList<Object>();
l.add( new Employee() );
l.add( new String() );
Object o = l.get( 0 );
Object o2 = l.get( 1 );
Finally
List<?>
Will let you assign any type, including
List <?> l = new ArrayList();
List <?> l2 = new ArrayList<String>();
This would be called collection of unknown and since the common denominator of unknown is Object you will be able to fetch Objects ( a coincidence )
The importance of unknown comes when its used with subclassing:
List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles
List<? extends Collection> l = new ArrayList<String>(); // doesn't,
// because String is not part of *Collection* inheritance tree.
I hope using Collection as the type doesn't create confusion, that was the only tree that came to my mind.
The difference here, is that l is a collection of unknow that belongs to the Collection hierarchy.
To add to the already good answers here:
Method arguments:
List<? extends Foo>
good choice if you don't intend to alter the list, and only care that everything in the list is assignable to type 'Foo'. This way, the caller can pass in a List<FooSubclass> and your method works. Usually the best choice.
List<Foo>
good choice if you intend to add Foo objects to the list in your method. The caller may not pass in a List<FooSubclass>, as you intend to add a Foo to the List.
List<? super Foo>
good choice if you intend to add Foo objects to the list, and it's not important what else is in the list (ie, you are ok getting a List<Object> that contains a 'Dog' that has nothing to do with Foo).
Method return values
just like method arguments, but with the benefits reversed.
List<? extends Foo>
Guarantees that everything in the returned List has type 'Foo'. It might be List<FooSubclass> though. Caller cannot add to the List. This is your go-to choice and the most common case by far.
List<Foo>
Just like List<? extends Foo> but also allows the caller to add to the List. Less common.
List<? super Foo>
allows the caller to add Foo objects to the List, but does not guarantee what will be returned from list.get(0)... it could be anything from Foo to Object. The only guarantee is that this won't be a list of 'Dog' or some other choice that would prevent list.add(foo) from being legal. Very rare use case.
I hope that helps. Good luck!
ps. To sum up... two questions...
do you need to add to the List? Do you care what is in the list?
yes yes - use List<Foo>.
yes no - use List<? super Foo>.
no yes - use <? extends Foo> --- most common.
no no - use <?>.
I refer you to the excellent Java Generics tutorial, and the "advanced" Generics tutorial, both available from Sun Microsystems. Another great resource is the Java Generics and Collections book.
I will try to answer this in detail. Before generics we were having only List (a raw list) and it can hold almost anything we can think of.
List rawList = new ArrayList();
rawList.add("String Item");
rawList.add(new Car("VW"));
rawList.add(new Runnable() {
#Override
public void run() {
// do some work.
}
});
The major problem with the raw list is when we want to get any element out of such list it can only guarantee that it would be Object and for that reason we need to use casting as:
Object item = rawList.get(0); // we get object without casting.
String sameItem = (String) rawList.get(0); // we can use casting which may fail at runtime.
So conclusion is a List can store Object (almost everything is Object in Java) and always returns an Object.
Generics
Now lets talk about generics. Consider the following example:
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
stringsList.add(new Car("Fiat")); //error
String stringItem = stringsList.get(0);
In the above case we cannot insert anything other than String in stringsList as Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. And we get error when we try to insert a Car instance in it. Also it eliminates cast as you can check when we invoke get method. Check this link for understanding why we should use generics.
List<Object>
If you read about type erasure then you will understand that List<String>, List<Long>, List<Animal> etc. will be having different static types at compile time but will have same dynamic type List at run time.
If we have List<Object> then it can store only Object in it and almost everything is Object in Java. So we can have:
List<Object> objectList = new ArrayList<Object>();
objectList.add("String Item");
objectList.add(new Car("VW"));
objectList.add(new Runnable() {
#Override
public void run() {
}
});
Object item = objectList.get(0); // we get object without casting as list contains Object
String sameItem = (String) objectList.get(0); // we can use casting which may fail at runtime.
It seems List<Object> and List are same but actually they are not. Consider the following case:
List<String> tempStringList = new ArrayList<>();
rawList = tempStringList; // Ok as we can assign any list to raw list.
objectList = tempStringList; // error as List<String> is not subtype of List<Obejct> becuase generics are not convariant.
You can see we can assign any list to raw list and major reason for that is to allow backward compatibility. Also List<String> will be converted to List at run time due to type erasure and assignment will be fine anyways.
But List<Object> means it can only refer to a list of objects and can also store objects only. Even though String is subtype of Object we cannot assign List<String> to List<Object> as generics are not covariant like arrays. They are invariant. Also check this link for more. Also check the difference between List and List<Object> in this question.
List<?>
Now we are left with List<?> which basically means list of unknown type and can refer to any list.
List<?> crazyList = new ArrayList<String>();
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
crazyList = stringsList; // fine
The character ? is known as wildcard and List<?> is a list of unbounded wildcard. There are certain points to observe now.
We cannot instantiate this list as the following code will not compile:
List<?> crazyList = new ArrayList<?>(); // any list.
We can say a wildcard parameterized type is more like an interface type as we can use it to refer to an object of compatible type but not for itself.
List<?> crazyList2 = new ArrayList<String>();
We cannot insert any item to it as we don't know what actually the type would be.
crazyList2.add("Apple"); // error as you dont actually know what is that type.
Now question arises When would I want to use List<?>?
You can think of this as a read-only list where you don't care about the type of the items. You can use it to invoke methods like returning the length of the list, printing it etc.
public static void print(List<?> list){
System.out.println(list);
}
You can also check the difference between List, List<?>, List<T>, List<E>, and List<Object> here.
Simplest explanation which is not "RTFM":
List
Will generate lots of compiler warnings, but is mostly equivalent to:
List<Object>
While:
List<?>
basically means its something generic, but you don't know what the generic type is. Its great for getting rid of compiler warnings when you cant modify the return types of other things that just returned List. Its much more useful in the form:
List<? extends SomeOtherThing>
The shortest possible explanation is: The second item is a list that can hold any type, and you can add objects to it:
List<Object>
The first item you list is treated as essentially equivalent to this, except you will get compiler warnings because it is a "raw type".
List
The third is a list that can hold any type, but you cannot add anything to it:
List<?>
Basically, you use the second form (List<Object>) when you truly have a list that can contain any object and you want to be able to add elements to the list. You use the third form (List<?>)when you receive the list as a method return value and you will iterate over the list but never add anything to it Never use the first form (List) in new code compiling under Java 5 or later.
I'd put it this way: While List and List<Object> can contain any type of objects, List<?> contains elements of an unknown type, but once that type is captured, it can only contain elements of that type. Which is why it is the only type safe variant of those three, and therefore generally preferable.
To complement the tutorials mentioned by Rob, here's a wikibook explaining the topic:
http://en.wikibooks.org/wiki/Java_Programming/Generics
Edit:
No restrictions on type of items in list
Items in list must extend Object
Wildcard used by itself, so it matches anything
Would it be naive of me to conclude at this point that there's hardly any/no difference at all?
When would I want to use
public void CanYouGiveMeAnAnswer( List l ){}
When you cant to do all the casting your self.
When would I want to use
public void CanYouGiveMeAnAnswer( List l<Object> ){}
When you want to restrict the type of the List. For instance, this would be an invalid argument.
new ArrayList<String>();
When would I want to use
public void CanYouGiveMeAnAnswer( List l<?> ){}
Mostly never.
List, List<?>, and List<? extends Object> are the same thing. The second is more explicit. For a list of this type, you cannot know what types are legal to put into it, and you don't know anything about the types you can get out of it, except that they will be objects.
List<Object> specifically means that the list contains any sort of object.
Let's say we make a list of Foo:
List<Foo> foos= new ArrayList<Foo>();
It is not legal to put a Bar into foos.
foos.add(new Bar()); // NOT OK!
It is always legal to put anything into a List<Object>.
List<Object> objs = new ArrayList<Object>();
objs.add(new Foo());
objs.add(new Bar());
But you mustn't be allowed to put a Bar into a List<Foo> - that's the whole point. So that means that this:
List<Object> objs = foos; // NOT OK!
is not legal.
But it's ok to say that foos is a list of something but we don't know specifically what it is:
List<?> dontKnows = foos;
But that then means that it must be prohibited to go
dontKnows.add(new Foo()); // NOT OK
dontKnows.add(new Bar()); // NOT OK
because the variable dontKnows does't know what types are legal.
List < Object > is meant to pass input type parameter of an Object. While List < ? > represents Wildcard type. The wildcard < ? > is of Unknown parameter type. The wildcard cannot be used as a type argument for a generic method and cannot be used to create a generic instance of a class. Wildcard can be used to extend a subtype class, List < ? extends Number >. To relax the restriction of an Object type and in this case to relax "Number" Object type.
In terms of List functionality differences, the other responses already answered this question. In terms of applicable rules of Java generics, it's a complicated topic. I wrote an in-depth article about Java generics rules, this is the link: https://medium.com/#royalilin/java-generics-rules-1d05de86e9cb