3

What I would like to have is something like this:

public abstract Class Content {
    private Map<Class<? extends Content>, List<? extends Content>> relations;
}

Content has a bunch of subclasses - A,B,C,D etc...

The most frequent use case is to get all A's:

public List<A> getA() {
    return (List<A>)relations.get(A.class);
}

Kind of ok - apart from the ugly cast.

But the real problem is there's nothing stopping me from doing something stupid like:

relations.put(A.class, List<B> myListOfBs);

So a call to getA() above would result in a horrible cast exception. Is there any way I can write it so the compiler would warn me in the above example - and also remove the need for the ugly cast.

Thanks

2 Answers 2

3

You can create a wrapper around a Map and use a generic method to constrain your put method:

 public class HeterogeneousContainer {
     private final Map<Class<? extends Content>, List<? extends Content>> map;

     public <T extends Content> void put(Class<T> type, List<T> values) {
         map.put(type, values);
     }


     public <T extends Content> List<T> get(Class<T> type) {
         //this warning can be safely suppressed after inspection
         return (List<T>) map.get(type); 
     }
 }

Now you know that as long as the users of the container aren't using it improperly (i.e. in raw form) then the key and value must correspond...you couldn't call put(B.class, listOfAs);.

Sign up to request clarification or add additional context in comments.

Comments

0

Create a custom Map interface that fixes the type to the same type:

interface RelatedMap<T> extends Map<Class<T>, List<T>> {}

then

private RelatedMap<? extends Content> relations;

2 Comments

This seems like a cool idea, but doesn't actually work in practice. You can't add anything to relations because Java can't deal with the capture problem. E.g. you can't do RelatedMap<? extends CharSequence> relations; relations.put(String.class, new ArrayList<String>());.
Also it can't work because it would be type unsafe: RelatedMap<String> strings; RelatedMap<?> anything = strings; anything.put(Integer.class, Arrays.asList(1, 2)); String str = strings.values().iterator().next().get(0); <-- type error

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.