Reputation: 45
I need to store variable and value as a pair somewhere and I tend to use Map. The problem is the type of value would be different so I think generic should be used. So I tried something like this:
Map<String, T> netPara;
and of course it does not work, then I tried
Map<String, Object> netPara;
This worked but when I retrived value it returned only of type Object, instead of "boolean", "int".
Can anyone help me out? I believe it tends to be simple but I am not an expert, yet. Thanks in advance.
In fact I have a function A who receives a list of parameters, but then it's function B who will also use these parameters but B's parameters list is vide, so I hope to store them as a class parameter and reused by function B. So here is what I did:
Class Person() {
Map<String, T> infoPaire; // if I use Object to replace T
Function A: receiver(boolean b, int i, String1 st1, String2 st2) {
infoPaire.put("b", b);
infoPaire.put("i", i);
infoPaire.put("st1", st1);
infoPaire.put("st2", st2);
}
Function B: user() {
boolean b = infoPaire.get("b"); // I need to add (boolean) to cast and I dont want it, it's ugly
int i = infoPaire.get("i");
String st1 = infoPaire.get("st1");
String st2 = infoPaire.get("st2");
}
Upvotes: 1
Views: 2589
Reputation: 2504
You need to understand generic and type-casting first. As far as your question is concerned, Object Class stood on top level in inheritance, means Object is the parent class of All java classes.
So you can cast any object in into Object class with out casting, but when you need to get you object back in its actual class you have to cast it. like String str = (String) netPara.get(key);
you need to look into polymorphism, casting, and generic concepts. Generic come to solve the problem you are facing right now.
Upvotes: 0
Reputation: 1981
I see now that you are asking a slightly different question than I had originally thought. I will leave my other answer up though, since it explains why this is a problem.
Since you are only dealing with Strings
, Booleans
, and Integers
you could do what you are asking by only storing Strings
in your Map
and converting to the proper type later.
Map<String, String> m = new HashMap<>();
m.put("bool", "true");
m.put("int", "1");
Integer i = Integer(m.get("int"));
Boolean b = Boolean(m.get("bool"));
This would be pseudo safe, but you would have to track the types for the values somewhere else in your code.
Probably the best solution would be to use three Maps
, one for each type.
Map<String, String> stringMap;
Map<String, Integer> intMap;
Map<String, Boolean> boolMap;
There is really no harm in having three maps, in general.
For reasons why you can't use one map cleanly, see my other answer on this question.
Upvotes: 1
Reputation: 1981
T
needs to be defined as a generic parameter on either the class or the method.
public <T> Map<String, T> getMap(){
return new HashMap<String, T>();
}
public class Test <T> {
public Map<String, T> getMap(){
return new HashMap<String, T>();
}
}
When using the method
Test t = new Test();
Map<String, Double> m = t.<Double>getMap();
or more concisely,
Map<String, Double> m = t.getMap();
Since the Double
can be inferred from the right hand side.
With a class.
Test<String> t = new Test<String>;
or with type inference,
Test<String> t = new Test<>;
And
Map<String, Integer> m = t.getMap()
And all together,
Test<String> t = new Test<>;
Map<String, String> m = t.getMap();
Test<Integer> t2 = new Test<>;
Map<String, Integer> m2 = t2.getMap();
For the type inference stuff, i.e. <>
and t.getMap()
with no type parameter, you must be using Java 7 or greater.
Using generics allows you to create code that manipulates values without knowing what they are, but there are some caveats. With reference to your question, it sounds like you might be trying to store two values of different type in the Map
, like so,
m.put('int', 7)
m.put('bool', true)
This would not be possible. Because T
, while generic, must eventually resolve to a single type for instance of the class. For instance,
Map<String, Integer> m;
This map could only ever hold Integer
values.
The reason that declaring Object
as the value works is because every class in Java is a subclass of Object
, so anything can go in there. But using Object
is very bad design. You are essentially turning off the type system, which is one of the major advantages that a language like Java brings to the table, static typing.
So, if you find yourself wanting to store a collection of homogeneous values, you might want to reconsider your design. Even in languages which explicitly allow such things (scheme, python, JavaScript, etc.) it is usually a sign of a design flaw to use them in a homogeneous manner.
Upvotes: 3
Reputation: 109547
You want something like
BigDecimal n = dictionary.get("n");
String s = dictionary.get("s");
which could have
class Dictionary {
public <T> T get(String name) { ... }
Because of the type erasure (the compiled/run-time code no longer knowing the generic types), you cannot do this, cast the object to return as T.
The solution:
BigDecimal n = dictionary.get(BigDecimal.class, "n");
String s = dictionary.get(String.class, "s");
which could be implemented with run-time cast exceptions:
public class Dictionary {
private Map<String, Object> map = new HashMap<>();
public <S> S put(Class<S> type, String name, S value) {
Object oldValue = map.put(name, value);
return type.cast(oldValue);
}
public <T> T get(Class<T> type, String name) {
Object value = map.get(name);
return type.cast(value);
}
}
One could store the type itself, maybe as additional key, a Map<Class<?>, Map<String, Object>>>
, but one still would not have gained much in this too open problem context.
Upvotes: 0
Reputation: 196
Following is the way to put elements into the map check it once
public class TakingInput {
public static void main(String[] args) {
Map<String,Object> map=new HashMap<String,Object>();
Integer in=new Integer(123);
Object obj=in;
String s=new String("suresh");
Object obj2=s;
map.put("hi",obj);
map.put("ramesh",obj2);
System.out.println(map);
//to retrive
String ss=(String) map.get("ramesh"); //type casting
System.out.println(ss); //o/p:suresh
}
}
Upvotes: 0
Reputation: 424993
The best you can hope for is a type of Object for value and a typed getter method that has an unsafe cast:
class VariableMap extends HashMap<String, Object> {
public <T> T getValue(Object key) {
return (T)super.get(key);
}
{
Upvotes: 0
Reputation: 206786
You can make one of the types a type parameter, but then you must also declare it as a type parameter. Just giving it a one-letter name such as T
does not automatically make it a type parameter.
class MyClass<T> { // Note: T is a type parameter
private Map<String, T> netPara;
// ...
}
Upvotes: 0