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.
Related
To achieve.
A method signal should take
any Object N
any of the Object's superclasses Class<?super N>
<N>void
signal(N n, Class<?super N> n_super)
{
/*...*/
}
It should be ok to call
Object object=new Object();
signal(object, object.getClass());
since Object is a super type of object. But calling it gives a waring. In IDE words:
IntelliJ (Android Studio)
Wrong 2nd argument type. Found Class<? extends Object>, required: Class<? super Object>
Eclipse
The method signal(N, Class<? super N>)
is not applicable for the arguments (Object, Class<? extends Object>)
Questions.
Can the goal be achieved, the way I have tried, and if yes,
how can the warning be eliminated
Turning my comments into an answer.
Two approaches I can quickly think of:
Use Object.class directly here. signal(object, Object.class); compiles fine with no warnings on my java version.
Change your method signature to something like:
<N, M extends N> void signal(N n, Class<? super M> n_super)
which should let you call it the way you already are (as in signal(object, object.getClass());).
use something like this:
Object object=new Object();
Class c = object.getClass();
signal(object, c);
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...
Consider the following 2 method declarations:
1. public abstract <T extends MetaData> List<T> execute();
2. public abstract List<? extends MetaData> execute();
Both seem to return back a list of objects that extend MetaData.
What is the difference between them please?
In the first case you will allow Java to use type inference and infer the type of T at each call site.
In the second case you will always get a List<? extends MetaData> and so won't be able to assign it to a variable of any narrower type like List<IntegerMetaData>.
If there are any subtypes of MetaData then the first version can only return an empty list or null. The second version may return a list containing instances of MetaData and its subtypes.
Example: Say A and B are subtypes of MetaData and execute returns a list containing an instance of A. The caller might have called execute like so:
List<B> list = execute(); // the second version does not allow this
The caller said he wanted a list of Bs, but got a list containing an A. Due to type erasure the implementation of execute has no way of knowing what the caller asked for. Thus the first version can't be implemented (except to return null or an empty list).
In example 1, you cannot must return a List whose generic type is T, e.g.:
#Override
public <T extends MetaData> List<T> execute() {
List<T> l = new ArrayList<T>();
return l;
}
In example 2, you can return a List whose generic type is just MetaData, e.g.:
#Override
public List<? extends MetaData> execute2() {
List<MetaData> l = new ArrayList<MetaData>();
return l;
}
What is the difference? In the first case, the method has a generic type, T and you must return something that relates to that type. In the second case, you just return a generic type, but the method itself does not have a generic type.
I need to instantiate generic variable like Class>.
For example,
Class<? extends List<String>> = ...
Variant 1:
Class<? extends List<String>> clazz = LinkedList.class;
don't work - "Incompatible types".
Variant 2:
Class<? extends List> clazz = LinkedList.class;
work, but in this case List is a raw type - not good.
How to instantiate such variables?
There is not really a point in having Class<List<String>>, since it would be equivalent to Class<List<Integer>> (both being a reference to the raw List due to erasure).
Having said that, if your intention is to represent the List<String> type, this is possible, see TypeLiteral of Google Guice.
TypeLiteral<List<String>> type = new TypeLiteral<List<String>>() {};
System.out.println(type.getType()); //should print List<String>
The mechanism that makes it possible is reflection on static type declarations, in either class definition (class X extends Foo<Y>, Y is available through reflection, it is preserved in the bytecode), method definitions, etc. TypeLiteral uses the former, you may notice that it creates a brand new class, so the net effect is that your type parameter gets preserved. It's a nice workaround when you are really fighting against erasure.
You can't do it properly. Either use the raw type or use an unsafe cast.
List<String> myList = new ArrayList<String>();
Class<? extends List<String>> var = (Class<? extends List<String>>)myList.getClass();
You can write:
class ListString extends java.util.LinkedList<String> { }
Class<? extends java.util.List<String>> clazz = ListString.class;
However, given what Class represents, there isn't that much point. You are better off avoiding reflection wherever possible.
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...