Build iterator for an interface, using the child [duplicate] - java

I have a List<SubClass> that I want to treat as a List<BaseClass>. It seems like it shouldn't be a problem since casting a SubClass to a BaseClass is a snap, but my compiler complains that the cast is impossible.
So, what's the best way to get a reference to the same objects as a List<BaseClass>?
Right now I'm just making a new list and copying the old list:
List<BaseClass> convertedList = new ArrayList<BaseClass>(listOfSubClass)
But as I understand it that has to create an entirely new list. I'd like a reference to the original list, if possible!

The syntax for this sort of assignment uses a wildcard:
List<SubClass> subs = ...;
List<? extends BaseClass> bases = subs;
It's important to realize that a List<SubClass> is not interchangeable with a List<BaseClass>. Code that retains a reference to the List<SubClass> will expect every item in the list to be a SubClass. If another part of code referred to the list as a List<BaseClass>, the compiler will not complain when a BaseClass or AnotherSubClass is inserted. But this will cause a ClassCastException for the first piece of code, which assumes that everything in the list is a SubClass.
Generic collections do not behave the same as arrays in Java. Arrays are covariant; that is, it is allowed to do this:
SubClass[] subs = ...;
BaseClass[] bases = subs;
This is allowed, because the array "knows" the type of its elements. If someone attempts to store something that isn't an instance of SubClass in the array (via the bases reference), a runtime exception will be thrown.
Generic collections do not "know" their component type; this information is "erased" at compile time. Therefore, they can't raise a runtime exception when an invalid store occurs. Instead, a ClassCastException will be raised at some far distant, hard-to-associate point in code when a value is read from the collection. If you heed compiler warnings about type safety, you will avoid these type errors at runtime.

erickson already explained why you can't do this, but here some solutions:
If you only want to take elements out of your base list, in principle your receiving method should be declared as taking a List<? extends BaseClass>.
But if it isn't and you can't change it, you can wrap the list with Collections.unmodifiableList(...), which allows returning a List of a supertype of the argument's parameter. (It avoids the typesafety problem by throwing UnsupportedOperationException on insertion tries.)

As #erickson explained, if you really want a reference to the original list, make sure no code inserts anything to that list if you ever want to use it again under its original declaration. The simplest way to get it is to just cast it to a plain old ungeneric list:
List<BaseClass> baseList = (List)new ArrayList<SubClass>();
I would not recommend this if you don't know what happens to the List and would suggest you change whatever code needs the List to accept the List you have.

The most efficient and at the same time safe way of accomplishing this is as follows:
List<S> supers = List.copyOf( descendants );
The documentation of this function is here: oracle.com - Java SE 19 docs - List.copyOf() The documentation states that this function exists "Since: 10".
The use of this function has the following advantages:
It is a neat one-liner.
It produces no warnings.
It does not require any typecast.
It does not require the cumbersome List<? extends S> construct.
It does not necessarily make a copy !!!
Most importantly: it does the right thing. (It is safe.)
Why is this the right thing?
If you look at the source code of List.copyOf() you will see that it works as follows:
If your list was created with List.of(), then it will do the cast and return it without copying it.
Otherwise, (e.g. if your list is an ArrayList(),) it will create a copy and return it.
If your original List<D> is an ArrayList<D>, then in order to obtain a List<S>, a copy of the ArrayList must be made. If a cast was made instead, it would be opening up the possibility of inadvertently adding an S into that List<S>, causing your original ArrayList<D> to contain an S among the Ds, which is a disastrous situation known as Heap Pollution (Wikipedia): attempting to iterate all the Ds in the original ArrayList<D> would throw a ClassCastException.
On the other hand, if your original List<D> has been created using List.of(), then it is unchangeable(*1), so it is okay to simply cast it to List<S>, because nobody can actually add an S among the Ds.
List.copyOf() takes care of this decision logic for you.
(*1) when these lists were first introduced they were called "immutable"; later they realized that it is wrong to call them immutable, because a collection cannot be immutable, since it cannot vouch for the immutability of the elements that it contains; so they changed the documentation to call them "unmodifiable" instead; however, "unmodifiable" already had a meaning before these lists were introduced, and it meant "an unmodifiable to you view of my list which I am still free to mutate as I please, and the mutations will be very visible to you". So, neither immutable or unmodifiable is correct. I like to call them "superficially immutable" in the sense that they are not deeply immutable, but that may ruffle some feathers, so I just called them "unchangeable" as a compromise.

I missed the answer where you just cast the original list, using a double cast. So here it is for completeness:
List<BaseClass> baseList = (List<BaseClass>)(List<?>)subList;
Nothing is copied, and the operation is fast. However, you are tricking the compiler here so you must make absolutely sure to not modify the list in such a way that the subList starts containing items of a different sub type. When dealing with immutable lists this is usually not an issue.

Below is a useful snippet that works. It constructs a new array list but JVM object creation over head is in-significant.
I saw other answers are un-necessarily complicated.
List<BaseClass> baselist = new ArrayList<>(sublist);

What you are trying to do is very useful and I find that I need to do it very often in code that I write.
Most java programmers would not think twice before implementing getConvertedList() by allocating a new ArrayList<>(), populating it with all the elements from the original list, and returning it. I enjoy entertaining the thought that about 30% of all clock cycles consumed by java code running on millions of machines all over the planet is doing nothing but creating such useless copies of ArrayLists which are garbage-collected microseconds after their creation.
The solution to this problem is, of course, down-casting the collection. Here is how to do it:
static <T,U extends T> List<T> downCastList( List<U> list )
{
#SuppressWarnings( "unchecked" )
List<T> result = (List<T>)list;
return result;
}
The intermediate result variable is necessary due to a perversion of the java language:
return (List<T>)list; would produce an "unchecked cast" warning;
in order to suppress the warning, you need a #SuppressWarnings( "unchecked" ) annotation, and good programming practices mandate that it must be placed in the smallest possible scope, which is the individual statement, not the method.
in java an annotation cannot be placed on just any line of code; it must be placed on some entity, like a class, a field, a method, etc.
luckily, one such annotatable entity is a local variable declaration.
therefore, we have to declare a new local variable to use the #SuppressWarnings annotation on it, and then return the value of that variable. (It should not matter anyway, because it should be optimized away by the JIT.)
Note: this answer was just upvoted, which is cool, but if you are reading this, please be sure to also read the second, more recent answer of mine to this same question: https://stackoverflow.com/a/72195980/773113

How about casting all elements. It will create a new list, but will reference the original objects from the old list.
List<BaseClass> convertedList = listOfSubClass.stream().map(x -> (BaseClass)x).collect(Collectors.toList());

Something like this should work too:
public static <T> List<T> convertListWithExtendableClasses(
final List< ? extends T> originalList,
final Class<T> clazz )
{
final List<T> newList = new ArrayList<>();
for ( final T item : originalList )
{
newList.add( item );
}// for
return newList;
}
Don't really know why clazz is needed in Eclipse..

This is the complete working piece of code using Generics, to cast sub class list to super class.
Caller method that passes subclass type
List<SubClass> subClassParam = new ArrayList<>();
getElementDefinitionStatuses(subClassParam);
Callee method that accepts any subtype of the base class
private static List<String> getElementDefinitionStatuses(List<? extends
BaseClass> baseClassVariableName) {
return allElementStatuses;
}
}

Related

Oracle's Collection<Object> tutorial is confusing

I'm learning Java generics and reading through Generic Methods.
This page starts with
Consider writing a method that takes an array of objects and a collection and puts all objects in the array into the collection
It then states
By now, you will have learned to avoid the beginner's mistake of trying to use Collection<Object> as the type of the collection parameter.
The page infers that using Collection<Object> won't work.
Why is that an error? Why is it a beginner's error?
Collection<Object> as the parameter works fine for me. Am I so beginner that I've somehow made code that works, but misses the point of the exercise?
import java.util.ArrayList;
import java.util.Collection;
public class test {
static void fromArrayToCol(Object a[],Collection<Object> c)
{
for (Object x:a){c.add(x);}
System.out.println(c);
}
public static void main(String[] args) {
test r=new test();
Object[] oa=new Object[]{"hello",678};
Collection<Object> c=new ArrayList<>();
test.fromArrayToCol(oa,c);
}
}
It looks to me like Oracle's tutorial is wrong in its assertion. But I'm a beginner, so it's likely that I'm not grasping what it's trying to tell me.
You can find the answer if you read the Wildcards section.
The problem is that this new version is much less useful than the old one. Whereas the old code could be called with any kind of collection as a parameter, the new code only takes Collection, which, as we've just demonstrated, is not a supertype of all kinds of collections!
Here, old version refers to parameter Collection whereas new code refers to Collection<Object>
When you have a parameter of type Collection<Object>you can pass either a Collection (raw type) or a Collection<Object>. You cannot pass any other collection like Collection<String> or Collection<SomeClass>.
So, the goal of that tutorial is to copy the elements of an array containing any type to a new collection of the same type.
Example: Integer[] to Collection<Integer>
I would say it wasn't worded properly to bring out the above meaning.
It's often a mistake not because it's a compiler error but because having a Collection<Object> is very rarely useful. Such a collection can hold anything. How often do you need a collection that can hold anything and everything? Very rarely. There will almost always be a more specific type parameter you can use for your collection.
Using Collection<Object> more often than not just makes a programmer's life harder than it needs to be. To get anything out of it we need to inspect it's type (e.g. use instanceof) and cast it.
By using the most appropriate type parameter, you give yourself compile-time assurance that the collection will only contain the types of objects that you expect it will and the resulting code is more concise and more readable.
the beginner's mistake they're referring to is the attempt to use Collection<Object> as parameter when you intend to accept Any
collection of something.
Because Object is superclass of all java class, one may think Collection<Object> is "super-collection" of all collection. This point is demonstrated in the Wildcard section:
The problem is that this new version is much less useful than the old one. Whereas the old code could be called with any kind of collection as a parameter, the new code only takes Collection, which, as we've just demonstrated, is not a supertype of all kinds of collections!
Instead of Collection<Object> you have to use Collection<T> to express that your method accept Any collection of something.
To clarify. If you do not know the type of a collection at compile time you cannot put an element in it.
In your current example, you do know the type of object you wish to put into the collection (In your case its an object). The example shown on the site you liked is
static void fromArrayToCollection(Object[] a, Collection<?> c) {
for (Object o : a) {
c.add(o); // compile-time error
}
}
Notice that there is an ? and not an Object. Hence you get a compile time error.
In the example you showed in your question which uses Object it does compile; however, there are better ways to solve this problem.
The biggest problem with that is that it only work on types that extend collection that have the generic type of Object. This makes it quite restrictive. The page is telling you that there is a way that will work for any collection and array as long as they hold the same type.
I think thats also a option:
private <T> void arrayToCollection(T[] objArray, Collection<T> collection) {
for (T obj : objArray) {
collection.add(obj);
}
}

Difference between two ways of type casting List to List<T>

public static <T> List<T> templatizeList(final List list, final Class<T> clazz) {
return (List<T>) list;
}
public static <T> List<T> typeSafeAdd(List<?> from, Class<T> clazz) {
List<T> to = new ArrayList<>();
from.forEach(item -> to.add(clazz.cast(item)));
return to;
}
What is the difference between the two methods? Is one way safer or faster than the other or it does not matter?
As per Java docs, generics are limited to compile time. They go away once the code compiles, this is called Type Erasure.
Now, regarding the methods, method 1 just adds a cast to the list without checking the type of all the elements present into it. Meaning, you may get an unexpected ClasscastException anywhere in code at runtime if the List is cast to Cat type and what comes out of it is a Dog.
Method 2 creates an entirely new list, it iterates through all the elements and tries to cast each element in target type. Meaning, it would fail if all the elements can't be cast to the target type.
I would say method 2 is safe as it makes sure everything is fine before adding a cast (i.e. localizes the risk). Method 1 may allow List (which contains Cat, Dog, Dinosaur) to be cast to List< Cat > and then, you may get unexpected failures.
This example explains it well.
Given the discussion, I'd like to suggest an option that combines the best of both worlds: it both localizes the risk of an unsafe cast AND it avoids creating a new List. And it's easy. (I'm making this community wiki since I'm just borrowing others' ideas.)
Step 1: Do the cast for each element from Method 2. Don't do anything with the result, just do the cast. That will ensure that a bad value will be caught right upfront.
Step 2: Do the List cast from Method 1.
Yet another idea
If you know that the List you got from Hibernate contains only the right type of element, then you can go ahead with Method 1. (The Eclipse JDT (at least prior to Mars) does the same thing in the AST. I have to deal with raw types far more often than I'd like.)
The difference is that in the first one you return the same list, while the second creates a new list.
I dont think there's a 'safer' of the two- since it eventually cast all list objecta on both, a non T object will cause classCastException on both.
The first is better in my mind- not creating a rather redundant new list
There is no way to determine whether the List really should have the generic parameters . You must know beforehand what the parameters should be (or you'll find out when you get a ClassCastException). This is why the code generates a warning, because the compiler can't possibly know whether it is safe.
If you want to support more generic data type,
then you can go with
public static <T> List<?> templatizeList(final List list, final Class<T> clazz) {
return (List<?>) list;
}
Otherwise,
2nd option makes sure that it is always of same type but it creates new List object...
So if you are sure then use either your 1st solution or my first option otherwise your second solution is decent removing the part it is creating new object.

Difference between ArrayAdapter<String> adapter and ArrayAdapter adapter? [duplicate]

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

Converting non-generic List type to Generic List type in Java 1.5

I have a List that is guaranteed to contain just one type object. This is created by some underlying code in a library that I cannot update. I want to create a List<ObjectType> based on the incoming List object so that my calling code is talking to List<ObjectType>.
What's the best way to convert the List (or any other object collection) to a List<ObjectType>.
When inter-operating with legacy code that doesn't specify type parameters for generic types, use a wildcard. For example, suppose you are calling a method in an older library that simply returns a raw Collection:
Collection getItems();
In your code, assign the result to a variable declared with a wildcard:
Collection<?> items = widget.getItems();
This way, you preserve type safety so you won't get any warnings.
The legacy code might specify (in a comment, most likely) what the generic parameters should be. For example:
/**
* #return the items, as a Collection of {#link Item} instances.
*/
Collection getItems();
In this case, you have a choice. You can cast the result to a Collection<Item>, but if you do so, you are relying 100% on the third-party library, and discarding the assurance of Java generic types: that any ClassCastException raised at runtime will occur right at an explicit cast.
What if you don't fully trust the third-party library, but still need to produce a Collection<Item>? Then create a new collection, and add the contents after casting them to the expected type. That way, if there is a bug in the library, you find out about it right away, rather than having some code far away and much later mysteriously blow up with a ClassCastException.
For example:
Collection<?> tmp = widget.getItems();
Collection<Item> items = new ArrayList<Item>(tmp.size());
for (Object o : tmp)
items.add((Item) o); /* Any type error will be discovered here! */
For a case where the type parameter isn't known at compile-time, you can use the type-checked collection factories of the Collections class.
You can simply cast the list:
List raw = new ArrayList();
List<String> generic = (List<String>) raw;
The best and safest way is to use java.util.Collections method 'checkedList(List list, Class type)'
With this method, all of the items in your old List will be checked as early as possible.
If you just cast to List<T> in any old place you will get an "unchecked" compiler warning. We resolved that by moving it to a utility method.
public class Lists {
#SuppressWarnings({"unchecked"})
public static <T> List<T> cast(List<?> list) {
return (List<T>) list;
}
}
Caller now gets no warning, e.g.:
for (Element child : Lists.<Element>cast(parent.getChildren())) {
// ...
}
That checkedList utility is in theory a great idea, but in practice it sucks to have to pass in the class you expect. I hope Java will get runtime generic typing information eventually.
Try this:
List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray());
But remember that this will produce a fixed length List. If you try to add or remove element from this list, it will throw an error. So be always careful while using Arrays.asList().

What does <E> mean in Collection<E>?

What meaning has <E> on the code Collection<E>?
It means that you're dealing with a collection of items with type E. Imagine you've got a cup of tea. Instead of tea, it could also hold coffee so it makes sense to describe the cup as a generic entity:
class Cup<T> { … }
now you could fill it, either with coffee or tea (or something else):
Cup<Tea> cuppa = new Cup<Tea>();
Cup<Coffee> foamee = new Cup<Coffee>();
In order for this to work, both Tea and Coffee would need to be types defined in your program as well.
This is a compile-time constraint on your code. Coming back from the (rather useless) cup example, collections (arrays, lists …) usually contain items of one type, e.g. integers or strings. Generics help you to express this in Java:
Collection<String> strList = new ArrayList<String>();
strList.add("Foobar"); // Works.
strList.add(42); // Compile error!
Notice the compile error above? You only get this when using generics. The following code also works, but would not give the nice error message:
Collection strList = new ArrayList();
strList.add("Foobar"); // Works.
strList.add(42); // Works now. Do we really want this?!
It's the use of generics. Check this intro out. And then don't forget to read this tutorial.
An excerpt follows (which compares the use of a cast versus the use of generics):
When you see the code <Type>, read it
as “of Type”; the declaration above
reads as “Collection of String c.” The
code using generics is clearer and
safer. We have eliminated an unsafe
cast and a number of extra
parentheses. More importantly, we have
moved part of the specification of the
method from a comment to its
signature, so the compiler can verify
at compile time that the type
constraints are not violated at run
time. Because the program compiles
without warnings, we can state with
certainty that it will not throw a
ClassCastException at run time. The
net effect of using generics,
especially in large programs, is
improved readability and robustness.
For example, the interface of a List is
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
This means you can build a list whose contents are all of the same explicit type (not only of type Object), even if you have defined the type yourself. So, if you create a Name class you can write
List<Name> nameList = new ArrayList<>();
and then fill it with Name instances and directly retrieve Name instances from it without having to cast or otherwise worry about it because you'll always get either a Name instance or null back, never an instance of a different type.
More importantly, you cannot insert anything different from a Name instance in such a List, because it will fail at compile time.
nameList.add(false); //Fails!
nameList.add(new Name("John","Smith")); //Succeeds supposing Name has a
//firstName, lastName constructor

Categories

Resources