Java Forum / General / May 2005
Generic Newbie HashMap Query
MrFredBloggs@hotmail.com - 02 May 2005 00:23 GMT import java.util.HashMap;
public class GenericMapTest { private HashMap<String, ? > map = null; private char type = '\0';
public GenericMapTest(char charIn) { super();
switch (charIn) { case 'S': type = charIn; map = new HashMap<String, String>(); break; case 's': type = 'S'; map = new HashMap<String, String>(); break; case 'I': type = charIn; map = new HashMap<String, Integer>(); break; case 'i': type = 'I'; map = new HashMap<String, Integer>(); break; } }
public void add(String stringIn) { switch (type) { case 'I': //BOUND MISMATCH: The method put(String, ?) of type //HashMap<String, ?> is not applicable for the arguments //(String, Integer). The wildcard parameter ? has no lower //bound and may actually be more restrictive than argument //Integer. map.put(stringIn, new Integer(stringIn.trim())); break; case 'S': //BOUND MISMATCH: The method put(String, ?) of type //HashMap<String, ?> is not applicable for the arguments //(String, String). The wildcard parameter ? has no lower //bound and may actually be more restrictive than argument //String. map.put(stringIn.trim(), stringIn.trim()); break; } } }
I'm new to generics.
Can the above errors be solved using the new Java5 generic coding techniques or is what I am trying to do just too silly in the first place.
Regards,
Fred.
Ross Bamford - 02 May 2005 01:09 GMT > import java.util.HashMap;
> Can the above errors be solved using the new Java5 generic coding > techniques or is what I am trying to do just too silly in the first > place. I think you need HashMap<String,Object> , or have I read you wrong?
 Signature [Ross A. Bamford] [ross AT the.website.domain] Roscopeco Open Tech ++ Open Source + Java + Apache + CMF http://www.roscopec0.f9.co.uk/ + info@the.website.domain
Ross Bamford - 02 May 2005 01:16 GMT > > import java.util.HashMap; > [quoted text clipped - 3 lines] > > I think you need HashMap<String,Object> , or have I read you wrong? sorry, HashMap<String,? extends Object> reading your post again.
 Signature [Ross A. Bamford] [ross AT the.website.domain] Roscopeco Open Tech ++ Open Source + Java + Apache + CMF http://www.roscopec0.f9.co.uk/ + info@the.website.domain
MrFredBloggs@hotmail.com - 02 May 2005 01:30 GMT Even HashMap<String, ? extends Object> gives the following errors:
import java.util.HashMap;
public class GenericMapTest { private HashMap<String, ? extends Object> map = null; private char type = '\0';
public GenericMapTest(char charIn) { super();
switch (charIn) { case 'S': type = charIn; map = new HashMap<String, String>(); break; case 's': type = 'S'; map = new HashMap<String, String>(); break; case 'I': type = charIn; map = new HashMap<String, Integer>(); break; case 'i': type = 'I'; map = new HashMap<String, Integer>(); break; } }
public void add(String stringIn) { switch (type) { case 'I': //BOUND MISMATCH: The method put(String, ? extends Object) //of type HashMap<String, ? extends Object> is not //applicable for the arguments (String, Integer). The //wildcard parameter ? has no lower bound and may actually //be more restrictive than argument Integer. map.put(stringIn, new Integer(stringIn.trim())); break; case 'S': //BOUND MISMATCH: The method put(String, ? extends Object) //of type HashMap<String, ? extends Object> is not //applicable for the arguments (String, String). The //wildcard parameter ? has no lower bound and may actually //be more restrictive than argument String. map.put(stringIn.trim(), stringIn.trim()); break; } } }
Ross Bamford - 02 May 2005 12:09 GMT > Even HashMap<String, ? extends Object> gives the following errors: Hmm, Now I see what you're saying.
It will compile if you change your method;
// --- public void add(String stringIn) { switch (type) { case 'I': { Map<String,Integer> tMap = (Map<String,Integer>)map; tMap.put(stringIn, new Integer(stringIn.trim())); break; } case 'S': { Map<String,String> tMap = (Map<String,String>)map; tMap.put(stringIn.trim(), stringIn.trim()); break; } } } // ---
But this of course generates two unchecked exceptions, rendering the whole thing pointless.
There are others who know more about this that I do (John?) so perhaps there is another way to do it, but I think you would need to create a generic class, such as:
<T extends Object> class MyValue<T> { public void set(<T> val) public <T> get() }
(thats paraphrased btw but you get the idea). This you could then add to your map, creating your instances as new MyValue<String>, MyValue<Integer>, and so on, and setting the value appropriately (possibly via constructor).
Hope this helps, Ross
 Signature [Ross A. Bamford] [ross AT the.website.domain] Roscopeco Open Tech ++ Open Source + Java + Apache + CMF http://www.roscopec0.f9.co.uk/ + info@the.website.domain
MrFredBloggs@hotmail.com - 02 May 2005 15:02 GMT ...that's great !!
I see what you mean.
However, having written your generic entry class as advised it appears that Eclipse 3.16M won't compile it, it doesn't seem to understand any of the <T> tokens. Anyway I see what you mean and will keep trying with this approach.
Regards,
Fred.
Ross Bamford - 02 May 2005 17:01 GMT > ...that's great !! > [quoted text clipped - 8 lines] > > Fred. Sorry it was a typo - the tokens should be <T> in signatures, but just straight T when referenced within the class:
class MyValue<T extends Object> { T value = null; public void set(T val) { value = val; } public T get() { return value; } }
 Signature [Ross A. Bamford] [ross AT the.website.domain] Roscopeco Open Tech ++ Open Source + Java + Apache + CMF http://www.roscopec0.f9.co.uk/ + info@the.website.domain
MrFredBloggs@hotmail.com - 02 May 2005 01:18 GMT These are the errors I get if I use HashMap<String, Object>.
import java.util.HashMap;
public class GenericMapTest { private HashMap<String, Object > map = null; private char type = '\0';
public GenericMapTest(char charIn) { super();
switch (charIn) { case 'S': type = charIn; //TYPE MISMATCH: Cannot convert from //HashMap<String,String> //to HashMap<String, Object>. map = new HashMap<String, String>(); break; case 's': type = 'S'; //TYPE MISMATCH: Cannot convert from //HashMap<String,String> //to HashMap<String, Object>. map = new HashMap<String, String>(); break; case 'I': type = charIn; //TYPE MISMATCH: Cannot convert from //HashMap<String,Integer> //to HashMap<String, Object>. map = new HashMap<String, Integer>(); break; case 'i': type = 'I'; //TYPE MISMATCH: Cannot convert from //HashMap<String,Integer> //to HashMap<String, Object>. map = new HashMap<String, Integer>(); break; } }
public void add(String stringIn) { switch (type) { case 'I': map.put(stringIn, new Integer(stringIn.trim())); break; case 'S': map.put(stringIn.trim(), stringIn.trim()); break; } } }
Chris Uppal - 02 May 2005 14:36 GMT > Can the above errors be solved using the new Java5 generic coding > techniques or is what I am trying to do just too silly in the first > place. I don't know whether it's /silly/ because I don't know what you are trying to achieve, but it does seem pretty weird to me.
Anyway, you can't make dynamically typed operations pass a static type check like that provided by Java generics. So you have two options: give up on static type checking (in this instance), or give up on the idea of using /one/ collection for two different purposes. I'm no great fan of static type checking, but in this case it does seem likely that the latter option makes more sense.
-- chris
John C. Bollinger - 02 May 2005 17:01 GMT > import java.util.HashMap; > [quoted text clipped - 63 lines] > techniques or is what I am trying to do just too silly in the first > place. What you are trying to do is OK, but your approach is largely missing the point of generics.
You have declared variable "map" to be of type HashMap<String, ?>, which, according to the Generics tutorial, should be read something like "HashMap from Strings to unknowns". It is important to understand that "unknown" does not mean "any type"; rather it means "some specific type that is not known at compile time". That's why you get type safety warnings when you try to put values into the map. Note also that that makes complete sense: nothing in the code you provided enables the compiler to verify that you didn't assign a HashMap<String, String> to map and then try to add an Integer to it.
To solve the problem you have to devise a way to "capture" the appropriate type information via the type declarations. Because your class wraps a Map that multiple methods use, the variable type parameters of the Map are going to need to be connected with type parameters of the class. That means that a particular instance of the class will be associated with a particular value type for the Map. Here is an example:
import java.util.HashMap; import java.util.Map;
public class GenericMapTest<T> { Map<String, T> map;
GenericMapTest() { map = new HashMap<String, T>(); }
public void add(T value) { // NOTE: important difference here map.put(value.toString(), value); // and here } }
To create on of these, you would use "new GenericMapTest<Integer>()" (for instance). Note the simplicity of the example compared to yours: one of the positive joys of generics is that they completely sidestep the kind of complicated type handling that so dominated your example. (At the expense of introducing sometimes-cryptic declarations.)
 Signature John Bollinger jobollin@indiana.edu
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|