是否可以定义Map <string,list <?=“” extend =“” baseview =“” >>,以便我可以从地图获取()列表而无需未经检查的转换?

时间:2018-07-19 09:30:29

标签: java generics collections casting

我有以下Java代码来获取与多个位置的对象相关的多个集合:

Map<String, List<? extends BaseView>> additionalCollections = deployEnvironmentService.getInputPageInfo(getProjectOid());
List<MachineView> machineViews = (List<MachineView>) additionalCollections.get("machineViewCollection");
List<LevelView> levelViews = (List<LevelView>) additionalCollections.get("levelViewCollection");
List<ToolView> toolViews = (List<ToolView>) additionalCollections.get("toolViewCollection");
List<BuildEnvironmentView> buildEnvironmentViews = (List<BuildEnvironmentView>) additionalCollections
                .get("buildEnvironmentViewCollection");

集合的名称和数量根据我使用的服务而有所不同,但是集合始终继承自BaseView。可以使用类似于以下方法的方法来检索集合:

public Map<String,List<? extends BaseView>> getInputPageInfo(Integer projectOid) {
    Map<String,List<? extends BaseView>> allInfoMap = new HashMap<String,List<? extends BaseView>>();
    PersistenceBroker broker = PersistenceBrokerFactory.createPersistenceBroker();
    try {
        allInfoMap.put("levelViewCollection", getLevelViewCollection(broker, projectOid));
        allInfoMap.put("machineViewCollection", getMachineViewCollection(broker));
        allInfoMap.put("toolViewCollection", getToolViewCollection(broker, projectOid));

        allInfoMap.put("buildEnvironmentViewCollection", getBuildEnvironments(broker, projectOid));

    } finally {
        broker.close();
    }
    return allInfoMap;
}

我遇到的问题是,我总是在第一个代码段的Map.get()方法上收到警告,说Type safety: Unchecked cast from List<capture#1-of ? extends BaseView> to Collection<LevelView>。有没有办法解决这个警告?我尝试定义类型<T extends BaseView>,但后来找不到在函数调用本身中使用该类型T的方法。

2 个答案:

答案 0 :(得分:0)

不,你不能。
您只能安全地强制转换为=IF(E2="",C1,CHAR(COUNTIF($E$2:E2,E2)+64)),因为您可以确保地图中的每个列表都包含BaseView可以对其进行扩展。
根据{{​​3}}的建议,您可以创建一个包含所有必要列表的类。

如果您绝对需要使用BaseView作为键,则可以通过自己进行类型检查来实例化一个不可修改的映射,而只是取消警告。

答案 1 :(得分:0)

将地图包装在“查找”对象中,然后键入密钥:

public final class PageInfoKey<T extends BaseView> {
    public static final PageInfoKey<MachineView> MACHINE_VIEWS
            = new PageInfoKey<>("machineViews", MachineView.class);
    /*... more static final keys defined here ...*/

    /* Adding the 'name' and 'type' fields,
     * and equals() and hashCode() as below,
     * allow us to have multiple instances of keys
     * defined elsewhere if desired, which should still
     * work with the lookup.
     *
     * If all keys are defined statically inside this class
     * (i.e. constructor is made private), then these fields
     * and methods are unnecessary.
     */

     private final String name;
     private final Class<T> type;

     public PageInfoKey(String name, Class<T> type) {
         this.name = name;
         this.type = type;
     }

     @Override
     public int hashCode() {
         return Objects.hash(name, type);
     }

     @Override
     public boolean equals(Object other) {
         if(other==this) return true;
         if(other instanceof PageInfoKey) {
             PageInfoKey<?> o = (PageInfoKey<?>)other;
             return Objects.equals(this.name, o.name) &&
                     Objects.equals(this.type, o.type);
         }
         return false;
     }
}

public class PageInfoLookup {

    private final Map<PageInfoKey<?>, List<? extends BaseView>> data = new HashMap<>();

    public <T extends BaseView> void put(PageInfoKey<T> key, List<T> value) {
        data.put(key, value);
    }

    @SuppressWarnings("unchecked")
    public <T extends BaseView> List<T> get(PageInfoKey<T> key) {
        return (List<T>) data.get(key);
    }

}

现在,您可以通过传入静态定义的键来获取视图:

List<MachineView> machineViews = lookup.get(PageInfoKey.MACHINE_VIEWS);

所有内容都是类型安全的,并在编译时进行检查,前提是您只能通过lookup类中的公共方法修改/访问地图。也不需要只在PageInfoKey类内定义键-只要该类上有明智定义的equalshashCode方法,您就可以在任意位置定义新实例,包括在依赖库中。

正如Aleksander所指出的那样,如果您知道地图中最多只会有一个特定类型的列表,那么您可以只使用Class本身作为键。 / p>