Why this is wrong:
Class<? extends Number> type = Integer.class;
ArrayList<type> = new ArrayList<>();
?
Is there no way to instantiate a class of a specific type given a class object?
Obviously I would never do that directly, that is just an example to show what is needed. In the actual code I need I don't know the name of the type. For example
public void createAList(Class<? extends Number> type)
{
ArrayList<type> toReturn = new ArrayList<>();
return toReturn;
}
<T extends Number> ArrayList<T> createAList(Class<T> type)
{
ArrayList<T> toReturn = new ArrayList<>();
return toReturn;
}
ArrayList<Integer> intList = createAList(Integer.class);
That's not how you use generics. You don't use a Class object, you use the class name directly in your code.
ArrayList<Integer> = new ArrayList<>();
Feel the difference between java Class (which actually generic too) object and class name.
You should use class name specifying generic type.
ArrayList<Number> = new ArrayList<>();
// ArrayList<Number.class> = new ArrayList<>(); <- WRONG
UPD:
Use this approach if you'll know type only in runtime:
public <T extends Number> void createAList(Class<T> type) {
ArrayList<T> toReturn = new ArrayList<>();
return toReturn;
}
An ArrayList<> has to have a specific type it holds . You can put objects of that type or any sub-type in it though.
So use
List<Number> = new ArrayList<Number>();
and you can put Integers in it
Notice how I used the interface on the left and the class on the right of the equal sign. That's a best practice sort of thing.
If you want a list that will just hold Integer (as per your example) the answer by #irreputable is your best bet. This answer will hold Integer but not just Integer.
Taken literally, the other answers' suggestions of how to implement createAList are ignoring something important: due to type erasure, such a method is pointless.
Given you want a List<? extends Number>, you can just write this:
List<? extends Number> lst = new ArrayList<>();
If you just wanted a List<?>, you could write:
List<?> lst = new ArrayList<>();
If you were in the scope of a type parameter T and wanted a List<T>, you could write:
List<T> lst = new ArrayList<>();
Notice that a Class object has nothing to do with these constructor calls, just like the methods in the other answers. That's because at runtime, the ArrayList instance doesn't know or care about whatever generic type its references had at runtime.
You don't even need to pass in an argument:
public <T extends Number> ArrayList<T> createAList () {
return new ArrayList<T>();
}
Though you may need to explicitly specify the type parameter when calling:
ArrayList<Integer> intList = this.<Integer>createAList();
ArrayList<type> = new ArrayList<>();
this line is wrong. First, you missed identifier (variable name) here; Second, you mixed the concepts of "type" and "class". You can delcare
ArrayList<Integer> list = new ArrayList<>();
But according to yours, type = Integer.class. Obviously, Integer is not equivalent to Integer.class. Similarly you can't have Integer.class i = 1; The former one is a "type", the second one is a "Class" object.
You can create a generic method:
public <T extends Number> List<T> createAList (Class<T> type) {
return new ArrayList<T>();
}
Related
So I was looking over some Java code and stumbled upon:
List<? extends SomeObject> l;
basically this list accepts all objects that are some kind of SomeObject - SomeObject itself or its inheritors. But according to polymophism, it's inheritors can also be seens as SomeObject, so this would work as well:
List<SomeObject> l;
So why would someone use the first option when the second is clearly defined and virtually identical?
List<SomeObject> l;
In this you cannot say List<SomeObject> l = new ArrayList<SubClassOfSomeObjectClass>;(not allowed)
wheres for
List<? extends SomeObject> l;
you can say
List<? extends SomeObject> l = new ArrayList<SubClassOfSomeObject>;(allowed)
But note that in List<? extends SomeObject> l = new ArrayList<SubClassOfSomeObject>; you cannot add anything to your list l because ? represents unknown class (Except null of-course).
Update: For your question in the comment What could I possibly do with a list if I cannot add anything to it?
Now consider a case in which you have to write a function to print your list but mind you it must only accept a List having objects which are subclasses of your SomeObject. In this case as I stated above you cannot use
public void printList(List<SubClassOfSomeObjectClass> someList)
So what would you do? You would do something like
public void printList(List<? extends SomeObject> someList) {
for(SomeObject myObj : someList) {
//process read operations on myObj
}
The key link you want to read is http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html which explains Generic wildcard in detail.
The List<SomeObject> is not the same as List<? extends SomeObject>. Observe the following
List<Object> x = new ArrayList<Object>();
List<String> y = new ArrayList<String>();
// x = y; Will throw Compilation exception
List<? extends Object> z = y; //will pass compilation
You may want to observe that you can add say a String to both the x and the y list however it will be useful when you write say a library function (such as the printCollection in the example shown in the link) rather than accepting a Collection<Object> in which case a user cannot pass his list of strings that he has to your method, if you accept Collection<? extends Object> then the user can pass his Collection<Apple>, Collection<Orange> etc without having to explicitly create another list.
List<? extends SomeObject> l; is not accepting new SomeObject()
but List<SomeObject> l; does.
what is also not working:
List<SomeObject> l = new ArrayList<SubTypeOfSomeObject>()
what is working:
List<? extends SomeObject> l = new ArrayList<SubTypeOfSomeObject>()
X cannot be added to List<Y> even if X can be converted to Y.
So,in your second case if List<X> l; was allowed to add subclass of X,that would break the basic principal of type safety
As the first answer,
List<? extends SomeObject> l;
must contains Object that inherit from SomeObject, not some direct SomeObject.
having
class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;
since cannot do
List<BaseClass> aList = new ArrayList<ChildClassA>()
so there is a
List<? extends IData> aList
for pointint to either
ArrayList<ChildClassA>(),
or
ArrayList<ChildClassB>()
the aList is built by other routing at runtime, and that part of code has a function to take a List<IData> from the the aList
the question is if the List<? extends IData> aList is point to ArrayList<ChildClassA>() or ArrayList<ChildClassB>(),
can it do ListData<IData> outputList = (List<IData>) aList? something like below:
(seems it is working, but not sure if there is better way to assign the generics array other than casting.)
Edit: the output of the List<IData> outputList is for read only use (immutable), no insert/delete on it, it will only iterate the IData to react on what the IData really is.
List<? extends IData> aList = new ArrayList<ChildClassA>();
ListData<IData> outputList = (List<IData>)aList
List<? extends IData> aList = new ArrayList<ChildClassB>();
ListData<IData> outputList = (List<IData>)aList
tl;dr Use Collections#unmodifiableList:
List<IData> outputList = Collections.unmodifiableList(aList);
For more information on this topic, you might want to get familiar with the PECS principle.
It's not possible, because the two types are incompatible.
A List<BaseClass> is just what it is declared, a list of BaseClass objects. More precisely, it makes two guarantees:
objects retrieved from it are assignable to BaseClass
every object that is assignable to BaseClass can be added to it (and no other)
A List<? extends BaseClass> is a more loose declaration. Precisely, it simply does not make the second guarantee. However, not only the guarantee is gone, but it is now impossible to add items to it, since the exact generic type of the list is undefined. It might even change for the same list declaration (not the same list object) at runtime.
As a consequence, a List<? extends BaseClass> is not assignable to a List<BaseClass>, since the latter makes a guarantee the first is unable to fulfill.
Practically speaking, consider the following method:
public List<BaseClass> makeList() {
// TODO implement method
return null;
}
If someone implements this method, returning a List<? extends BaseClass>, a client using this method would be unable to add items to it, although its declaration indicates otherwise.
Because of that, such an assignment results in a compilation error.
To fix the example problem the loose declaration can be added to the method:
public List<? extends BaseClass> makeList() {
// TODO implement method
return null;
}
This will signal every client, that the list returned from this method is not meant for adding items to it.
Now let's get back to your use case. In my opinion the most appropriate fix is to the rephrase the function that
take[s] a List from the the aList.
As it seems it is currently declared as
public void useList(List<BaseClass> list);
but since it does not add items to the list, it should be declared as
public void useList(List<? extends BaseClass> list);
However, if that method is part of a currently unchangeable API, you can still do:
List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);
No, it is unsafe.
After that cast it would be legit to add to the list that is supposed to contain only ChildClassA typed elements, element of the other child type ChildClassB type and vice-versa.
We can simply your code a bit to make it more obvious why this should not be allowed:
List<ChildClassA> aList = new ArrayList<ChildClassA>();
aList.add(a1);
aList.add(a2);
//...
List<IData> iDataList = (List<IData>) aList;
iDataList.add(b1);
iDataList.add(b2);
//...
for (ChildClassA a : aList) {
// a some point a is going to be assigned b1 or b2 and they results in cast
// exception.
}
Note that iDataList makes reference to the very same list object as aList.
If that cast was allowed then you would be able to add elements to aList that are not ChildClassA instances.
The best solution is on the details.
If the problem is that a third-party library requires a List<IData> typed reference and as long as it is only for reading you can use a unmodifiable proxy as returned by Collections.unmodifiableList:
import java.util.Collections;
//...
final List<ChildClassA> aList = new ArrayList<>();
//... add stuff to aList
final List<IData> readOnlyIDataList = Collections.unmodifiableList(aList);
//... read only access operations readOnlyIDataList
Given:
import java.util.*;
public class Hancock {
//insert code here
list.add("foo");
}
}
Which two code fragments, inserted independently at line 5, will compile without warnings? (Choose two)
A. public void addString(List list) {
B. public void addString(List<String> list) {
C. public void addString(List<? super String> list) {
D. public void addString(List<? extends String> list) {
Correct answers are B & C.
Answers A and B are quite clear for me. For the answers C & D i know which way the inheritence is going, however i cannot understand why answer D does not compile in Eclipse while all others do (A with warrning about generic, B & C without warrings).
Error in Eclipse for answer D is The method add(capture#1-of ? extends String) in the type List<capture#1-of ? extends String> is not applicable for the arguments (String).
On the other hand this compiles:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
Why? Why <? super String> does not compile in method declaration while it does compile in variable declaration.
I know that String is final class and cannot be extended by any other class but that does not explain to me what is going on here.
First, let's see answer C:
public void addString(List<? super String> list) {
list.add("foo");
}
This method declaration says that you will be allowed to pass List objects which are parametrized by some super class of String, for example String or Object. So:
If you pass List<String> the list.add("foo") will be perfectly valid.
If you pass List<Object> the list.add("foo") will be perfectly valid, because "foo" is a String (and you can add a String to a List<Object>).
This means that answer C is correct.
Lets now see answer D.
If you have a method declaration like this:
public void addString(List<? extends String> list) {
}
this means that you will be able to pass List objects parametrized by some unknown subtype of String. So, when you do list.add("foo"); the compiler won't be aware if the provided object has a type that matches the unknown subtype of String and therefore raises a compile-time error.
When you have:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
This fragment compiles fine, because list1 is defined to hold List objects that are of some unknown subtype of String, including the String itself, which is why it's valid.
The problem is that you won't be able to add anything, except null.
As for list2, the variable can hold List objects which are parametrized by some super-type of String, including the String itself.
More info:
What is PESC?
What is the difference between super and extends in Java wildcards?
Firstly, generics don't care that String is final. They work the same way for final and non-final classes.
With that in mind, it should be apparent why D is not allowed - if it was, you could do this:
void test() {
List<Integer> integers = new ArrayList<Integer>();
addADouble(integers);
int a = integers.get(0); // ????
}
void addADouble(List<? extends Number> list) {
list.add(new Double(5.0));
}
List<? extends Number> is a "List of something that extends Number, but you don't know exactly what it's a List of." - it might be a List<Double>, or a List<Integer>, or a List<Number>, or a List<YourCustomSubclassOfNumber>, so you can't add anything to it because you don't know if it's the right type.
I have two questions, actaully...
First off, Why cant I do this:
List<Object> object = new List<Object>();
And second, I have a method that returns a List<?>, how would I turn that into a List<Object>, would I be able to simply cast it?
Thank you!
Why cant I do this:
List<Object> object = new List<Object>();
You can't do this because List is an interface, and interfaces cannot be instantiated. Only (concrete) classes can be. Examples of concrete classes implementing List include ArrayList, LinkedList etc.
Here is how one would create an instance of ArrayList:
List<Object> object = new ArrayList<Object>();
I have a method that returns a List<?>, how would I turn that into a List<Object>
Show us the relevant code and I'll update the answer.
List<Object> object = new List<Object>();
You cannot do this because List is an interface and you cannot create object of any interface or in other word you cannot instantiate any interface. Moreover, you can assign any object of class which implements List to its reference variable. For example you can do this:
list<Object> object = new ArrayList<Object>();
Here ArrayList is a class which implements List, you can use any class which implements List.
List is an interface so you can't instanciate it. Use any of its implementatons instead e.g.
List<Object> object = new List<Object>();
About List :
you can use any object as a generic param for it instance:
List<?> list = new ArrayList<String>();
or
List<?> list = new ArrayList<Integer>();
While using List<Object> this declaration is invalid because it will be type missmatch.
To answer your second question, yes, you can cast the List<?> as a List<Object> or a List<T> of any type, since the ? (Wildcard) parameter indicates that the list contains a homogenous collection of an any Object. However, there's no way to know at compile what the type is since it's part of the exported API only - meaning you can't see what's being inserted into the List<?>.
Here's how you would make the cast:
List<?> wildcardList = methodThatReturnsWildcardList();
// generates Unchecked cast compiler warning
List<Object> objectReference = (List<Object>)wildcardList;
In this case you can ignore the warning because in order for an object to be used in a generic class it must be a subtype of Object. Let's pretend that we're trying to cast this as a List<Integer> when it actually contains a collection of Strings.
// this code will compile safely
List<?> wildcardList = methodThatReturnsWildcardList();
List<Integer> integerReference = (List<Integer>)wildcardList;
// this line will throw an invalid cast exception for any type other than Integer
Integer myInteger = integerRefence.get(0);
Remember: generic types are erased at runtime. You won't know what the collection contains, but you can get an element and call .getClass() on it to determine its type.
Class objectClass = wildcardList.get(0).getClass();
package com.test;
import java.util.ArrayList;
import java.util.List;
public class TEst {
public static void main(String[] args) {
List<Integer> ls=new ArrayList<>();
ls.add(1);
ls.add(2);
List<Integer> ls1=new ArrayList<>();
ls1.add(3);
ls1.add(4);
List<List<Integer>> ls2=new ArrayList<>();
ls2.add(ls);
ls2.add(ls1);
List<List<List<Integer>>> ls3=new ArrayList<>();
ls3.add(ls2);
m1(ls3);
}
private static void m1(List ls3) {
for(Object ls4:ls3)
{
if(ls4 instanceof List)
{
m1((List)ls4);
}else {
System.out.print(ls4);
}
}
}
}
I have a list of lists.
I would like to know how I can restrict the generic types of each of the inner lists so each element of the outer list contains an inner list that can only contain one type of object. So far I have tried this:
List<ArrayList<?>> l = new ArrayList<ArrayList<?>>();
But there are ways to add types of objects to the inner lists which do not belong. Is there a way to specify the type the inner list accepts?
For example, if I have the following inner lists,
ArrayList<T1> innerList = new ArrayList<T1>();
ArrayList<T2> innerList2 = new ArrayList<T2>();
ArrayList<T3> innerList3 = new ArrayList<T3>();
How would I create an outer list which can contain all of the inner lists while retaining the specific type that the inner list contains.
Also I am not sure if this is possible, or if what I am doing is bad design. If it is bad design, insight onto a better design (maybe there is a different collection that does this better) would be very appreciated.
If the types of the inner lists have nothing in common, there is no way to narrow it down, and the wildcard ? is the best you can do.
If T1 T2 and T3 all extend from a base class B, then you can write:
List<List<? extends B>> outerList = new ArrayList<List<? extends B>>();
Or likewise if they share an interface. It depends on what common functionality they are implementing that requires them to be stored in the same list.
If you want help with the design you will need to explain your situation with an example/use case. It's probably not good design to keep them in the same collection if they have nothing in common.
This is not possible. Generic information is only available at compile time. However, the exact contents and structure of a list of lists will not be known until runtime. Thus, the compiler, cannot make any assurances about what each list will contain. If you do know in advance the structure of the list then it would be better to consider a holding class eg.
class Holder<T,S> {
List<T> listOfTs;
List<S> listOfSs;
}
If you know that the lists will all share a common supertype then you may wish to use wildcard bounding.
List<List<? extends Shape>> list = new ArrayList<List<? extends Shape>>();
list.add(new ArrayList<Circle>());
list.add(new ArrayList<Square>());
This will allow you to manipulate the lists according to their supertype. The problem with wildcard bounding is that you cannot add any elements to wildcard bounded collections.
Consider the following:
List<? extends Shape> list = new ArrayList<Circle>();
list.add(new Square());
// element is a valid shape, but not a valid circle
// contract of the original list is broken.
If you know you are only ever going to use a certain number of generics you could store the class that each represents and use this to cast the lists in a type safe way.
class ListHolder<T> {
private final Class<T> clazz;
private final List<T> list;
public ListHolder(Class<T> clazz) {
this.clazz = clazz;
this.list = new ArrayList<T>();
}
public boolean isCircleList() {
return this.clazz == Circle.class;
}
public List<Circle> getCircleList() {
if (!isCircleList()) {
throw new IllegalStateException("list does not contain circles");
}
return (List<Circle>) list;
}
public boolean isRectangleList() {
return this.clazz == Rectangle.class;
}
public List<Rectangle> getRectangleList() {
if (!isRectangleList()) {
throw new IllegalStateException("list does not contain rectangles");
}
return (List<Rectangle>) list;
}
public static void main(String[] args) {
ListHolder<Rectangle> rectangleListHolder = new ListHolder<Rectangle>(Rectangle.class );
List<ListHolder<? extends Shape>> list = new ArrayList<ListHolder<? extends Shape>>();
list.add(rectangleListHolder);
ListHolder<? extends Shape> shapeWildCardList = list.get(0);
List<Rectangle> rectangles = shapeWildCardList.getRectangleList();
}
}
If you have a fixed number of types which could go into such lists you could create a subtype for each of those types. This would also have the advantage that you could use instanceof to determine the type of your list, which you probably want to do if you have a list of differently typed lists.
// common supertype for the lists
abstract class SpecialList<T> extends LinkedList<T> {}
// a list for every type:
class T1List extends SpecialList<T1> {}
class T2List extends SpecialList<T2> {}
class T3List extends SpecialList<T3> {}
//use
List<SpecialList<?>> l = new ArrayList<SpecialList<?>>();