I have a Java question about generics. I declared a generic list:
List<? extends MyType> listOfMyType;
Then in some method I try instantiate and add items to that list:
listOfMyType = new ArrayList<MyType>();
listOfMyType.add(myTypeInstance);
Where myTypeInstance is just an object of type MyType; it won't compile. It says:
The method add(capture#3-of ? extends
MyType) in the type List<capture#3-of
? extends MyType> is not applicable
for the arguments (MyType)
Any idea?
You cannot do a "put" with extends . Look at Generics - Get and Put rule.
Consider:
class MySubType extends MyType {
}
List<MySubType> subtypeList = new ArrayList<MySubType>();
List<? extends MyType> list = subtypeList;
list.add(new MyType());
MySubType sub = subtypeList.get(0);
sub now contains a MyType which is very wrong.
You shouldn't need to use the wildcard capture syntax in your case, simply declaring
List<MyType> listOfMytype;
should be enough. If you want to know exactly why, the Java Generics Tutorial has more than you would ever want to know about the esoteric craziness of Java Generics. Page 20 addresses your specific case.
As for why add with the wildcard capture does not work, it is because the compiler can't determine exactly what subclass of MyType the list will be in every case, so the compiler emits an error.
There is a similar thread here:
How can elements be added to a wildcard generic collection?
To get an idea of how generics works check out this example:
List<SubFoo> sfoo = new ArrayList<SubFoo>();
List<Foo> foo;
List<? extends Foo> tmp;
tmp = sfoo;
foo = (List<Foo>) tmp;
The thing is, that wasn't designed for local/member variables, but for function signatures, that's why it's so ass-backwards.
I dont know if this will really help you, but this is something I had to use while calling a generic method of Spring Framework and wanting to return also a generic list:
public <T> List<T> findAll(String tableName,Class<?> table) {
String sql = "SELECT * FROM "+ tableName ;
List<?> entities = getSimpleJdbcTemplate().query(sql,
ParameterizedBeanPropertyRowMapper.newInstance(table));
return (List<T>) entities;
}
Seems the parametrization needs you to use the ? sign in the list to receive the results and then cast the list to the expected return type.
Iam still dazzled by generics...
Related
Suppose I have an object Class<?> c. Is it possible to create a generic list with c as the generic parameter?
So something like this:
Class<?> c = doSomething();
List<c> list = new ArrayList<c>();
No that is impossible - at least your grammar will not compile. However, you may try to learn generics in Java, and see whether that helps your specific case, as this may be a A-B problem.
For example, this works:
<T> int yourFunction(List<T> items) {
T item = items.get(0);
// play with the item of type T, yeah!
}
For Class<? extend T> clazz, List<T> can be used for any instance created by clazz. For Class<? super T> clazz, List<T> should only contain instance that are compatibly with clazz.
For Class<?>, List<Object> is probably what you want. Any use of reflection, including Class is usually a mistake.
While I was going through some generics question I came across this example. Will you please explain why list.add("foo") and list = new ArrayList<Object>() contain compailation issues?
In my understanding List of ? extends String means "List of Something which extends String", but String is final ? can only be String. In list.add() we are adding "foo" which is a string. Then why this compilation issue?
public class Generics {
public static void main(String[] args) {
}
public static void takelist(List<? extends String> list){
list.add("foo"); //-- > error
/*
* The method add(capture#1-of ? extends String) in the
* type List<capture#1-of ? extends String> is not applicable
* for the arguments (String)
*/
list = new ArrayList<Object>();
/*
* Type mismatch: cannot convert from ArrayList<Object> to List<? extends String>
*/
list = new ArrayList<String>();
Object o = list;
}
}
For starters, the java.lang.String class is final, meaning nothing can extend it. So there is no class which could satisfy the generic requirement ? extends String.
I believe this problem will cause all of the compiler errors/warnings which you are seeing.
list.add("foo"); // String "foo" does not extend String
list = new ArrayList<Object>(); // list cannot hold Object which does not extend String
It is true what you say. String is final. And so you can reason that List<? extends String> can only be list of string.
But the compiler isn't going to make that kind of analysis. That is to say, the compiler will not assess the final or non-final nature of String (see comments). The compiler will only let you put null into your list.
You can pull stuff out though.
String s = list.get(0);
While String is final, this information is not used.
And in fact, with Java 9, it may no longer be final (rumor has it that Java 9 may finally get different more efficient String types).
Without knowing it is final, List<? extends String> could be e.g. a List<EmptyString> of strings that must be empty.
void appendTo(List<? extends String> l) {
l.append("nonempty");
}
appendTo(new ArrayList<EmptyStrings>());
would yield a violation of the generic type.
As a rule of thumb always use:
? extends Type for input collections (get is safe)
? super Type for output collections (put is safe)
Type (or maybe a <T>) for input and output collections (get and put are safe, but the least permissive).
I.e. this is fine:
void appendTo(List<? super String> l) {
l.append("nonempty");
}
appendTo(new ArrayList<Object>());
You have already mentioned that String is a final type and therefore there is no point in repeating this fact. The point that is important to note is that none of the following Lists allows adding an element:
List<?> which is a List of anything.
List<? extends SomeType> which is a List of anything that extends SomeType.
Let's understand it with an example.
The List<? extends Number> could be List<Number> or List<Integer> or List<Double> etc. or even a List of some other type that hasn't been defined yet. Since you can not add any type of Number to a List<Integer> or any type of Number to a List<Double> etc., Java does not allow it.
Just for the sake of completeness, let's talk about List<? super Integer> which is List of anything that is a super/parent type of Integer. Will the following compile?
Object obj = 10.5;
list.add(obj);
As you can guess, of course NOT.
What about the following?
Object obj = 10.5;
list.add((Integer) obj);
Again, as you can guess, indeed it will compile but it will throw ClassCastException at runtime. The question is: why did not Java stop us in the first place by failing the compilation itself? The answer is Trust. When you cast something, the compiler trusts that you already understand the cast.
So, the following compiles and runs successfully:
Object obj = 10;
list.add((Integer) obj);
list.add(20);
I have a Java question about generics. I declared a generic list:
List<? extends MyType> listOfMyType;
Then in some method I try instantiate and add items to that list:
listOfMyType = new ArrayList<MyType>();
listOfMyType.add(myTypeInstance);
Where myTypeInstance is just an object of type MyType; it won't compile. It says:
The method add(capture#3-of ? extends
MyType) in the type List<capture#3-of
? extends MyType> is not applicable
for the arguments (MyType)
Any idea?
You cannot do a "put" with extends . Look at Generics - Get and Put rule.
Consider:
class MySubType extends MyType {
}
List<MySubType> subtypeList = new ArrayList<MySubType>();
List<? extends MyType> list = subtypeList;
list.add(new MyType());
MySubType sub = subtypeList.get(0);
sub now contains a MyType which is very wrong.
You shouldn't need to use the wildcard capture syntax in your case, simply declaring
List<MyType> listOfMytype;
should be enough. If you want to know exactly why, the Java Generics Tutorial has more than you would ever want to know about the esoteric craziness of Java Generics. Page 20 addresses your specific case.
As for why add with the wildcard capture does not work, it is because the compiler can't determine exactly what subclass of MyType the list will be in every case, so the compiler emits an error.
There is a similar thread here:
How can elements be added to a wildcard generic collection?
To get an idea of how generics works check out this example:
List<SubFoo> sfoo = new ArrayList<SubFoo>();
List<Foo> foo;
List<? extends Foo> tmp;
tmp = sfoo;
foo = (List<Foo>) tmp;
The thing is, that wasn't designed for local/member variables, but for function signatures, that's why it's so ass-backwards.
I dont know if this will really help you, but this is something I had to use while calling a generic method of Spring Framework and wanting to return also a generic list:
public <T> List<T> findAll(String tableName,Class<?> table) {
String sql = "SELECT * FROM "+ tableName ;
List<?> entities = getSimpleJdbcTemplate().query(sql,
ParameterizedBeanPropertyRowMapper.newInstance(table));
return (List<T>) entities;
}
Seems the parametrization needs you to use the ? sign in the list to receive the results and then cast the list to the expected return type.
Iam still dazzled by generics...
I have the following code:
public <T extends SomeObject> long doSomething(T someObject){
List<? extends SomeObject> l = new LinkedList<>();
l.add(someObject);
}
this causes a compilation error - telling me that there is no suitable methods found: add(T),
why is that?
If l accept things that extends SomeObject shouldn't it accept someObject as it bounds to extend SomeObject?
List<? extends SomeObject> l
What do you mean by that? Of course it will generate an error.
Take this example :SomeObject is Fruit, you have 2 derived classes Apple and Orange
Your list what will it contain? Apples or Oranges? The compiler cannot tell. So it generates error.
If you replace List<? extends SomeObject> l with List<SomeObject> l. Then this will work because Apple and Orange are both Fruit.
I would advise you to use this statement:
List<T> l = new LinkedList<T>();
This is no less type-safe then
List<SomeObject> l = new LinkedList<SomeObject>();
and additionally gives you an opportunity to get objects of type T from the list without casting. T is already SomeObject so no casting required to call methods of SomeObject on T.
And all that with less typing!
Back to the problem.
First thing to note is that wildcard type "?" means unknown, this is important.
You may, however, specify an upper (? extends) or a lower (? super) constraint to it.
You declared a list as "List".
List is known to have objects of SomeObject inside. but! the exact type of objects is unknown.
Compiler can not say if there are instances of "class A extends SomeObject" or instances of "class B extends SomeObject" inside the list.
If you call list.get() it can only say that there will be an object of type SomeObject.
SomeObject obj = list.get(1); // Ok
But inserting an object of any(!) type is unsafe because the actual type of elements in the list is unknown.
You could wonder why wildcard type ever exists.
It is here to lower restriction in type casting that will be too strict otherwise.
Sample
class A { }
class A2 extends A { }
class B <T> {
void change(T a) { .. };
T read() { .. };
}
If there were no wildcards we would not be able to do this: B<A> b = new B<A2>(); - it does not work.
This is because type conversion from B<A> to B<A2> is unsafe.
Why? Let's look (copied from http://en.wikipedia.org/wiki/Generics_in_Java)
List<Integer> ints = new ArrayList<Integer>();
ints.add(2);
List<Number> nums = ints; // valid if List<Integer> were a subtype of List<Number>
nums.add(3.14);
Integer x = ints.get(1); // now 3.14 is assigned to an Integer variable!
What is the solution? Sometimes, we want to do such assignments or pass parameters in a general way!
Wildcard type helps here: B<? extends A> b = new B<A2>();
Method B.void change(T a) is now disabled - this is what your question was about and explained in the first part.
Method B.T read() is still valid and returns A: A a = b.read();. Yes, it returns A2 actually but to the caller of b.read() it's visible as A.
Wildcard types are widely used in Collections Framework.
I have two classes with nested generics. Is there a way to get rid of the
Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>> error ?
In the last assignment
public class Value<V> {
V val;
public Value(V val) {
this.val = val;
}
#Override
public String toString() {
return "" + val;
}
}
public class Msg<T> {
T holder;
public Msg( T holder) {
this.holder = holder ;
}
public String toString() {
return "" + holder;
}
public static void main(String[] args) {
Msg<Value<String>>strMsg = new Msg(new Value<String>("abc"));
// This is OK
Msg<?>objMsg = strMsg;
// Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>>
Msg<Value<?>>objMsg = strMsg;
}
}
Use the following:
Msg<? extends Value<?>> someMsg = strMsg;
The problem is that the ? in Msg<Value<?>> objMsg is NOT capable of capture conversion. It's not "a Msg of Value of some type. It's "a Msg of Value of ANY type".
This also explains why along with the declaration change, I've also renamed the variable to someMsg. The Value can't just be any Object. It must belong to some type (String in this example).
A more generic example
Let's consider a more generic example of a List<List<?>>. Analogously to the original scenario, a List<List<?>> can NOT capture-convert a List<List<Integer>>.
List<List<Integer>> lolInt = null;
List<List<?>> lolAnything = lolInt; // DOES NOT COMPILE!!!
// a list of "lists of anything"
List<? extends List<?>> lolSomething = lolInt; // compiles fine!
// a list of "lists of something"
Here's another way to look at it:
Java generics is type invariant
There's a conversion from Integer to Number, but a List<Integer> is not a List<Number>
Similarly, a List<Integer> can be capture-converted by a List<?>, but a List<List<Integer>> is not a List<List<?>>
Using bounded wildcard, a List<? extends Number> can capture-convert a List<Integer>
Similarly, a List<? extends List<?>> can capture-convert a List<List<Integer>>
The fact that some ? can capture and others can't also explains the following snippet:
List<List<?>> lolAnything = new ArrayList<List<?>>(); // compiles fine!
List<?> listSomething = new ArrayList<?>(); // DOES NOT COMPILE!!!
// cannot instantiate wildcard type with new!
Related questions
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
Very long and detailed exploration into this problem
Java Generic List<List<? extends Number>>
Any simple way to explain why I cannot do List<Animal> animals = new ArrayList<Dog>()?
What is the difference between <E extends Number> and <Number>?
See also
Java Generics Tutorial
Generics and Subtyping | Wildcards | More Fun with Wildcards
Angelika Langer's Java Generics FAQ
What is a bounded wildcard?
Which super-subtype relationships exist among instantiations of generic types?
My answer is similar to another, but hopefully is more clear.
List<List<?>> is a list of (lists of anything).
List<List<String>> is a list of (lists of strings).
The latter cannot be converted to the former because doing so would allow you to add a List<Number> to your List<List<String>>, which would clearly be broken.
Note that the rules for this don't change if you replace List with some type that doesn't have .add. Java would need declaration-site covariance and/or contravariance for that (like C#'s IEnumerable<out T> or Scala's List[+A]). Java only has use-site covariance and contravariance (? extends X, ? super X).
Although your generic type parameter contains a wildcard, it is not itself a wildcard. When assigning to a variable (Msg<T>) with a non-wildcard generic type T, the object being assigned must have exactly T as its generic type (including all generic type parameters of T, wildcard and non-wildcard). In your case T is Value<String>, which is not the same type as Value<?>.
What you can do, because Value<String> is assignable to Value<?>, is use the wildcard type:
Msg<? extends Value<?>> a = new Msg<Value<String>>();
Not a direct answer but i strongly recommend the reading of: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf to better understand generics.
ILMTitan has a good solution, and if you don't want to make the class specific to Value you may as well use the base type instead of generics at this point because you'll be turning off a safety feature, but there is a way. You might even be able to pass a parameter to make this method more generic, but the key is "#SuppressWarnings".
#SuppressWarnings("unchecked")
Msg<Value<?>> convert()
{
return (Msg<Value<?>>) this;
}