Ensuring generic wildcards match in Java -
so understanding following:
hashmap<class<?>,list<?>> map
would allow insert pairing. how enforce can insert matched pairs. e.g.
map.put(string.class, new vector<string>()); map.put(integer.class, new vector<integer>());
but disallow following:
map.put(classa.class, new vector<classb>()); //i want refuse compile
is possible?
update: input far. understand abstracting away map insertion enforce common type across both parameters. keep map clean, how can guarantee compiler case.
e.g. cause compiler grumble, , no amount of casting seems fix (at least i've tried)
list<string> list1 = map.get(string.class);
so instead i'm using following i'm not happy it
list list2 = map.get(string.class);
nb i'm not in front of ide memory general idea clear.
i not directly use hashmap
, default methods has not allow desire. i'd write own collection based on hashmap
expose it's own put
method. this:
public <t> void put(class<t> clazz, list<t> list) { internalmap.put(clazz, list); }
assume internalmap
private member of collection class , of type hashmap<class<?>, list<?>>
. notice use of generic parameter method. call that:
mycollection.<integer>put(integer.class, new vector<integer>()); mycollection.<string>put(string.class, new vector<string>());
or that:
mycollection.put(integer.class, new vector<integer>()); mycollection.put(string.class, new vector<string>());
these not compile:
mycollection.<string>put(string.class, new vector<integer>()); mycollection.put(string.class, new vector<integer>());
update regarding latest comment op on question, , update of question itself:
how make more generic. e.g. replace list generic type defined @ class level. public void put (class clazz, t1 t1)...how ensure t1 can handle generic parameter?
well, can still this, additional generic parameter , type constraint. need use root base class or interface collection have, because need enforce generics appropriately. let's assume base type collection<t>
interface (vector
, arraylist
, many other collections implement interface). above put
method (i including imaginary class internalmap
definition):
public class classmap { private map<class<?>, collection<?>> internalmap = new hashmap<class<?>, collection<?>>(); public <t, tcollection extends collection<t>> void put( class<t> clazz, tcollection collection) { internalmap.put(clazz, collection); } public <t> collection<t> get(class<t> clazz) { // notice cast, important hide // "compiler grumble" mention in post return (collection<t>) internalmap.get(clazz); } }
the usage update cases explicit generic arguments:
mycollection.<integer, vector<integer>>put(integer.class, new vector<integer>()); mycollection.<string, arraylist<string>>put(string.class, new arraylist<string>());
and shorter version:
mycollection.put(integer.class, new vector<integer>()); mycollection.put(string.class, new arraylist<string>());
will work, due generic type inference.
the get
method, must have noted, uses collection<t>
interface. if introduce tcollection
generic argument in same manner in put method, have supply generic arguments. so, if method defined this:
public <t, tcollection extends collection<t>> tcollection get(class<t> clazz) { return (tcollection) internalmap.get(clazz); }
then have 2 problems:
- the call needs necessary ugliness:
arraylist<string> list
= mycollection.<string, arraylist<string>>get(string.class);
- you have no compile-time guarantee collection
arraylist<string>
(and thinking compile-time type safety important you), receive runtime-exception invalid cast if wrong. therefore,get
method not need introducetcollection
generic argument @ all, guaranteed workcollection<t>
interface (as values implement it). if interface not suitable (you need specific methods of , etc), you'd have either cast explicitly (with risks in mind), or use more-concrete interface root type constraint oftcollection
. instance, instead ofcollection<t>
, can uselist<t>
.
as bottom line, regarding use of tcollection
generic argument, can omitted. once add collection map, no longer know exact implementation used. so, above code same this:
public class classmap { private map<class<?>, collection<?>> internalmap = new hashmap<class<?>, collection<?>>(); public <t> void put(class<t> clazz, collection<t> collection) { internalmap.put(clazz, collection); } public <t> collection<t> get(class<t> clazz) { return (collection<t>) internalmap.get(clazz); } }
and used that:
mycollection.<integer>put(integer.class, new vector<integer>()); mycollection.<string>put(string.class, new arraylist<string>());
or that:
mycollection.put(integer.class, new vector<integer>()); mycollection.put(string.class, new vector<string>());
that same kocko's suggested answer
Comments
Post a Comment