简体   繁体   中英

Java: Declaring a Map with two related generics Types (<T> Map<Class<? extends ClassA<T>>,Class<? extends ClassB<T>>>)

Is it possible to declare a Map that maps from keys of a specific subclass to values of a specific subclass but ensuring that both classes share the same Type parameter?

For the background:

both ClassA and ClassB implement behaviour for a common resource

public abstract  class ClassA<T> {
      public abstract T getResource() ;
}

public abstract class classB<T> {
       public  abstract void consoumeResource(T resource);
}

i want to map from implementations of ClassA and ClassB and ensure only "compatible" pairs can be put together in one entry.

Another way would be to provide your own Map implementation. There's not much code needed if you extend an existing implementation, and use your new type:

public class CompatibleHashMap<T> extends HashMap<ClassA<T>, ClassB<T>> {

}

Now, a CompatibleHashMap<String> only lets you put ClassA<String> as keys and ClassB<String> as values.

EDIT:

As you mentioned in your comment, this way you are tying yourself to a Map implementation. You can overcome this by doing something like the following:

public class CompatibleMap<T> implements Map<ClassA<T>, ClassB<T>> {

    private Map<ClassA<T>, ClassB<T>> map;

    public CompatibleMap(Map<ClassA<T>, ClassB<T>> map) {
        this.map = map;
    }

    @Override
    public Set<List<T>> keySet() {
        return map.keySet();
    }
    // ... implement all other Map methods by calling the method on map.
}

You can then instantiate it like

CompatibleMap<String> map = new CompatibleMap<>(new HashMap<ClassA<String>, ClassB<String>>());

This way, you are not tied to a specific Map implementation, and the compiler will throw an error if the generic types of the map , ClassA and ClassB are not the same.

You can't do this in the Map declaration but you can do this using methods which access/update the map.

eg

private final Map<Class, Builder> builderMap = new LinkedHashMap<>();

public <T> void addBuilder(Class<T> tClass, Builder<T> tBuilder) {
     builderMap.put(tClass, tBuilder);
}

public <T> Builder<T> getBuilderFor(Class<T> tClass) {
    @SuppressWarnings("unchecked") 
    Builder<T> tBuilder = (Builder<T>) builderMap.get(tClass);
    return tBuilder;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM