Generic Newbie HashMap Query

M

MrFredBloggs

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.
 
R

Ross Bamford

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?
 
M

MrFredBloggs

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;
}
}
}
 
M

MrFredBloggs

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;
}
}
}
 
R

Ross Bamford

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
 
C

Chris Uppal

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
 
M

MrFredBloggs

....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.
 
R

Ross Bamford

...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.

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; }
}
 
J

John C. Bollinger

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.

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.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top