我使用Spring Boot .yaml进行配置,并使配置类成为层次结构,以便其他应用程序可以定义其他属性。配置本身具有层次结构。

为了保持扩展性,我使用了<? extends Type>通用声明。

当我尝试将<? extends Type>减小为Type时,这会导致问题。

以下完全正常工作的最小示例演示问题(在getSubConfs方法中):

public static class Conf<S> {
    public String name;
    public Map<String, S> subConfs;
}

public static class SubConf {
    public String name;
    public Conf<? extends SubConf> conf;
}

public static Map<String, SubConf> getSubConfs(SubConf subconf) {
    // incompatible types: java.util.Map<java.lang.String,capture#1 of ? extends App.SubConf>
    // cannot be converted to java.util.Map<java.lang.String,App.SubConf>
    return subconf.conf.subConfs;
}

public static void main(String[] args) {
    Conf<SubConf> cfg = new Conf<>();
    cfg.name = "cfg";
    SubConf subcfg = new SubConf();
    subcfg.name = "subcfg";
    subcfg.conf = cfg;
    cfg.subConfs = new HashMap<>();
    cfg.subConfs.put(subcfg.name, subcfg);

    Map<String, SubConf> subConfs = getSubConfs(subcfg);
    System.out.println(subConfs.get("subcfg").name);
}


我希望在getSubConfs(subcfg)调用时获得Map<String, SubConf>,因为我不在乎subcfg的进一步特殊化,我只需要访问公共属性。

有效代码为:

public static Map<String, ? extends SubConf> getSubConfs2(SubConf subconf) {
    Conf<? extends SubConf> cfg = subconf.conf;
    return cfg.subConfs;
}


但是我看不到为什么在运行时没有类型问题的情况下我应该在API中使用? extends SubConf的原因。

更新功能:

public static Map<String, SubConf> getSubConfs(SubConf subconf) {
    Conf<? extends SubConf> cfg = subconf.conf;
    return (Map<String, SubConf>) cfg.subConfs;
}


表明即使使用-XLint:unchecked,代码也没有任何运行时问题:

warning: [unchecked] unchecked cast
    return (Map<String, SubConf>) cfg.subConfs;
required: Map<String,SubConf>
found:    Map<String,CAP#1>
where CAP#1 is a fresh type-variable:
  CAP#1 extends SubConf from capture of ? extends SubConf


当然,我可以用@SuppressWarnings("unchecked")装饰函数。

最佳答案

您的方法getSubConfs()的问题是SubConf.conf的类型为Conf<? extends SubConf>。那么Conf.subConfs的类型为Map<String, ? extends SubConf>,但是此Map与您要获取的Map<String, SubConf>不兼容。

不兼容的原因是,没有办法说明Map<String, ? extends SubConf>中的SubConf实现。您可以从中读取SubConf值,但不能在其中添加任何内容(最终可能会混合使用不同的实现)。 Map<String, SubConf>清楚其类型,您可以安全地阅读和添加项目:

// Assuming SubConf2 and SubConf3 both extend SubConf ...
HashMap<String, SubConf2> map = new HashMap<>();
Map<String, ? extends SubConf> subconfMap = map;
// This doesn't work, because then you could call map.get("key")
// and get SubConf3 which is not compatible with the declared SubConf2
subconfMap.put("key", new SubConf3());

// The problem cannot happen with with Map<String, SubConf>, because
// the following statement causes compile time error:
Map<String, SubConf> subconfMap = new HashMap<String, SubConf2>();

关于java - 如何减少泛型<?将Type>扩展为Java中的Type。代码在运行时有效,但无法编译,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43627743/

10-10 10:05