Java map generic value

Get generic type for java.util.Map parameter

Is there a possibility to figure out the generic types (key / value) of my Map parameter via Reflection?

I don’t fully understand the question, but I think the answer might be in the code for Collection.toArray().

5 Answers 5

I know this question is old, but the best answer is wrong.
You can easily get the generic types via reflections. Here an example:

private Map genericTestMap = new HashMap(); public static void main(String[] args) < try < Field testMap = Test.class.getDeclaredField("genericTestMap"); testMap.setAccessible(true); ParameterizedType type = (ParameterizedType) testMap.getGenericType(); Type key = type.getActualTypeArguments()[0]; System.out.println("Key: " + key); Type value = type.getActualTypeArguments()[1]; System.out.println("Value: " + value); >catch (Exception e) < e.printStackTrace(); >> 

This will get you the output:
Key: class java.lang.String
Value: class java.lang.Integer

The accepted answer is correct. You are retrieving the generic type of the declaration. This is not the same problem as retrieving the compile-time generic type of an object instance for which the generic type information has been erased. Specifically the OP typed the Map parameter without any generic parameters (implicitly ) from which this information could be recovered. Your answer, while useful for your specific case, does not address the question.

Источник

I’m trying to create a generic type that keeps a map of the versions of itself that have been created for later use. Effectively, it’s an singleton pattern where there’s one instance per type. The code I have so far is:

public class FieldBinder < static final Map,FieldBinder> instanceMap = new HashMap,FieldBinder>(); private FieldBinder() <> synchronized public static FieldBinder getInstance(Class klass) < if(!instanceMap.containsKey(klass)) < instanceMap.put(klass, new FieldBinder()); > return (FieldBinder)instanceMap.get(klass); > > 

However, I’m still unsure that I’m «doing it right». It feels like I should be able to specify that the collection is (Class -> FieldBinder). The fact that the IDE is warning about the return statement only reinforces this thought. Is there a better way to handle this? Note: This question seems very closely related, but just far enough away that I can’t figure out how to apply the information in it to my own problem.

4 Answers 4

Your implementation is correct. There’s no «better» way of doing it (if there is such a thing is «better» in code, which is another issue..)

  • is equivalent to V which is less verbose
  • Class is equivalent to Class which is less verbose
  • You can use the @SuppressWarnings(«unchecked») annotation to tell your compiler that the cast is safe

I don’t think it can be done without having an unchecked cast somewhere. You would need something similar to Haskell’s existential types, which Java does not have.

You could make the client perform the unchecked cast instead.

synchronized public static FieldBinder getInstance(Class klass, Class binderKlass) < if(!instanceMap.containsKey(klass)) < instanceMap.put(klass, new FieldBinder()); > return binderKlass.cast(instanceMap.get(klass)); > 

Now if the client passes a Class> to the getInstance() method you can avoid the unchecked cast within getInstance() .

Unfortunately creating a Class> itself requires an unchecked cast.

Class> binderKlass = (Class>) (Class) FieldBinder.class; BinderAssociator.getInstance(Integer.class, binderKlass); 

RHSeeger, I got your original question. I found no solution for the problem. What you can try to play with is a MyMap class, which makes the binding as you request. However with this map two problems arise:

  1. As it is declared as MyMap , one cannot add something with a given type to it. That’s dummy and I refer you to Java Generics FAQs (see case study 3) for more details.
  2. As map has connection between key and value, one cannot add two independent objects of any type (two refer to different types) because these two types may be not connected.

While playing I have seen some errors, which I could not explain myself. I think, everything goes into the fact (as I mentioned before) that we try to deal with 2-nd level parametrization.

 class FieldBinder  < static class MyMapextends HashMap < >static final MyMap instanceMap1 = new MyMap(); static final Map instanceMap2 = new HashMap(); public static void test() < Classc1 = null; FieldBinder f1 = null; Class c2 = null; FieldBinder f2 = null; instanceMap1.put(c1, f1); // error (see 1) instanceMap1.put(c2, f2); // error (see 2) instanceMap2.put(c1, f1); // ok instanceMap2.put(c2, f2); // ok instanceMap2.put(c1, f2); // wish to be an error, but ok instanceMap2.put(c2, f1); // wish to be an error, but ok > > 

Источник

Java: make one of the Map<> variable generic

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:

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() < MapinfoPaire; // 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"); >

You need to go back to your design stage. What are you trying to accomplish with a mapping of a string to some object? What will you be doing with the retrieved object? How does the mapped item work with your Class model?

7 Answers 7

T needs to be defined as a generic parameter on either the class or the method.

Method

Class

public class Test  < public MapgetMap()< return new HashMap(); > > 

Usage

Method

Test t = new Test(); Map m = t.getMap(); 

Since the Double can be inferred from the right hand side.

Class

Test t = new Test<>; Map m = t.getMap(); Test t2 = new Test<>; Map m2 = t2.getMap(); 

Warning

For the type inference stuff, i.e. <> and t.getMap() with no type parameter, you must be using Java 7 or greater.

Other Warning About the Type System in General

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,

This would not be possible. Because T , while generic, must eventually resolve to a single type for instance of the class. For instance,

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.

Источник

How to add values for Java generic Map with undetermined «?» value type?

Both fail to compile. I wish to know: 1) What does ? indicate in Map declaration above? 2) How to give values to this map ?

3 Answers 3

Map is an abstract type. If a variable has this type, it could reference an object with any of the following types (and others).

Obviously, the possibilities are basically endless. If you have a variable of this type, you know that it refers to a map whose keys are String , but you really know nothing else. In particular, you don’t know what type of object you’ll end up with when you do a get on that Map .

More importantly though, you will never be able to put anything into the map, without some kind of nasty, unsafe casting operation. The compiler will stop you. So in the examples you’ve given —

  • map.put(«abc», Optional.of(5)); won’t compile, because map could be a HashMap , into which you can’t put an Optional .
  • map.put(«kk», «xyz»); won’t compile, because map could be a TreeMap , into which you can’t put a String .

The exceptions would be null , or any value that has come from the map itself — see Andy Turner’s excellent answer for more detail about those possibilities.

In short, if you have a variable of type Map , the operations that the compiler will let you do to it are a bit limited. You can’t put anything into the map, unless it’s null or it’s already in the map. All you can do is get values from the map, and remove values from the map.

So using a Map variable is very limiting. If all you want to do with the map is read values from it, this is just fine, of course. But don’t expect to be able to insert arbitrary values into the map, unless you use a different expression to refer to the map.

Источник

Generic Map in Java

Java’s Map interface ( java.util.Map ) can be generified. In other words, you can set the specific type of both the keys and values in a generic Map instance. Here is an example:

This Map can now only accept Integer instances as keys, and String instances as values.

The generic type checks only exists at compile time. At runtime it is possible to tweak your code so that other instances can be inserted. This is a bad idea, though.

Accessing a Generic Map

Adding and getting elements to a generic Map is done using the put() and get() methods, just like you have always done:

Map map = new HashMap; Integer key1 = new Integer(123); String value1 = "value 1"; map.put(key1, value1); String value1_1 = map.get(key1);

So what is the big difference? Well, if you try to add a key, value pair that is not a Integer, String pair instance, to the Map in the example above, the compiler will complain. That’s a pretty nice extra type check to have.

Also notice how it is not necessary to cast the String instance returned by the get() method. The compiler knows that this Map has String values, so casting is not necessary.

You can also use the new auto boxing features of Java 5 to make it easier to specify the Integer values, like this:

Map map = new HashMap; Integer key1 = 123; String value1 = "value 1"; map.put(key1, value1); //or map.put(123, value1); String value1_1 = map.get(123);

Iterating a Generic Map

A Map has two collections you can iterate. The key Set and the value Set . Most often you iterate the key Set and access the values for each key via the Map.get() method.

Map map = new HashMap; //. add key, value pairs to the Map // iterate keys. Iterator keyIterator = map.keySet().iterator(); while(keyIterator.hasNext()) < Integer aKey = keyIterator.next(); String aValue = map.get(aKey); >Iterator valueIterator = map.values().iterator(); while(valueIterator.hasNext())

Notice how it is not necessary to cast the object returned from the iterator.next() next call. Because the Map is generified (has a type), the compiler knows that it contains Integer instances for keys, and String instances for values. Therefore it is not necessary to cast the objects obtained from the Map , even if it comes from one of its Iterator ‘s.

You can also use the new for-loop, like this:

Map map = new HashMap; //. add key, value pairs to the Map for(Integer aKey : map.keySet()) < String aValue = map.get(aKey); System.out.println("" + aKey + ":" + aValue); >for(String aValue : map.values())

Notice how an Integer and a String variable is declared inside the parantheses of each for-loop. For each iteration (each element in the Map ‘s key set or value collection) this variable contains the current element (current Integer or String).

Источник

Читайте также:  Docker java heap space
Оцените статью