How to work with a generic map whose key and value

2019-07-05 08:09发布

问题:

My objective is to create a Map whose keys are Class instances and whose values are instances of the corresponding Class. Meaning,

Map (a certain class in a hierarchy --> its corresponding instance)

To do that, I declared Map like

Map<Class<? extends BaseService>, ? extends BaseService> serviceMap = 
    new HashMap<Class<? extends BaseService>, BaseService>();
//Assume BaseService is at the root of hierarchy.

The above compiles.

In order to populate the Map, I used

public <T extends BaseService> void register(T service) {   
    serviceMap.put(service.getClass(), service);    
}

This does not compile.

How do I make this work ? And why doesn't this compile ?

回答1:

Your use of wildcards isn't exactly consistent with your English definition. When you define:

Map<Class<? extends BaseService>, ? extends BaseService> serviceMap;

this might be described as "serviceMap is a map from Classes which extend BaseService, to some type of value (which is BaseService or a subclass)".

The compiler is correct to reject your register method in this context. serviceMap's value type is declared to be simply "something" - so you could easily assign a map to it with a value type of ServiceImplOne. And your register method could be called with an argument of class ServiceImplTwo. You can't insert this into the map as it's not consistent with the generic parameters!

It's clear that since you want to be able to insert any type of service, the map must accept all instances of BaseService as values, not some (unknown) subtype of BaseService. Therefore you can fix this by declaring the map with a concrete value type:

Map<Class<? extends BaseService>, BaseService> serviceMap;