EdgeCase
EdgeCase

Reputation: 4827

Can I avoid This Cast with Generics?

I want to store an Integer or a Double, both extending from Number, into a HashMap, and retrieve them without casting. The reason is that I'll eventually have many have many different subtypes (I am only using Number/Integer for illustration), and I don't want to have to write a new method when a different subtype is introduced. Can I structure and call getFromMap() below without having to do the cast to Double or Integer ?

public class MapOfContent {
    static Map<String, Number> hm = new HashMap<String, Number>();

    public static void main(String[] args) {
        addToMap(hm, Integer.valueOf(3), "An Integer");
        addToMap(hm, Double.valueOf(3.4), "A Double");

        Double d;

        d = (Double) getFromMap(hm, "A Double");
        //d = getFromMap(hm, "A Double");

        System.out.println("Result-> " + d);

    }

    private static void addToMap(Map<String, ? super Number> hashmap, Number c, String key) {
        hashmap.put(key, c);
    }

    private static <T> Number getFromMap(Map<String, ? extends Number> hashmap, String cmsKey) {
        return hashmap.get(cmsKey);
    }
}

Upvotes: 3

Views: 215

Answers (2)

biziclop
biziclop

Reputation: 49724

If you're storing objects of different classes in a collection and when you fetch them, you need to access fields/methods of their actual type and not just their common ancestor, then no.

There will be an explicit cast somewhere, the best you can do is to push it deep and hide it from all the other parts of the code, as ClassToInstanceMap does.

Upvotes: 0

Louis Wasserman
Louis Wasserman

Reputation: 198023

There's no way to actually make this approach genuinely typesafe; what if you tried (Double) getFromMap(hm, "An Integer")? That should fail.

One potential alternative might be to use the actual Class object as a key, for example using a Guava ClassToInstanceMap:

ClassToInstanceMap<Number> map = MutableClassToInstanceMap.create();
map.putInstance(Integer.class, Integer.valueOf(3));
map.putInstance(Double.class, Double.valueOf(3.4));

Double aDouble = map.getInstance(Double.class); // no cast required

Upvotes: 2

Related Questions