【问题标题】:Generic issues: T extends interface type. Cannot call method to return an object which extends the type?一般问题:T 扩展接口类型。无法调用方法返回扩展类型的对象?
【发布时间】:2016-09-13 16:28:37
【问题描述】:

我在父类中声明了这个方法:

protected <ConfigT extends LoadableConfig> ConfigT getConfig(final String configId) {
    return (ConfigT)getConfigService().getConfig(configId, getDriver());
}

配置服务方法定义如下:

@SuppressWarnings("unchecked")
@Override
public <ConfigT extends LoadableConfig> ConfigT getConfig(String configId, WebDriver driver) {

    //noinspection unchecked
    Map<String,LoadableConfig> profile = profiles.get(getProfileName(driver));

    if(profile != null) {
        return (ConfigT) profile.get(configId);
    }

    return null;
}

我要的配置类型在这里:

public interface AccessibleConfig extends LoadableConfig, PolleableConfig {
 ....
}

这行代码抛出了不兼容的类型错误:

 AccessibleConfig config = getConfig(ValidationPane.class.getCanonicalName());

这怎么可能? AccessibleConfig 扩展了 LoadableConfig。调用的方法声明该返回类型是扩展LoadableConfig 的某种类型。我正在运行 jdk1.8.0_102.jdk。此故障发生在 IntelliJ 以及从命令行使用 Maven 编译时。我可以使用扩展 LoadableConfig 类型的其他配置类型来做到这一点。

编辑:

父类:

public abstract class AbstractLoadable<T extends AbstractLoadable<T>> {

    private Map<String,LoadableConfig> profiles = new HashMap<>();

    protected <T extends LoadableConfig> T getConfig(final String configId) {
        return (T) profiles.get(configId);
    }
}

具体类:

public class ConcreteLoadable extends AbstractLoadable {

    public ConcreteLoadable(final String profileName) {

        AccessibleConfig config = getConfig(ConcreteLoadable.class.getCanonicalName());
    }

}

以及接口类型:

public interface LoadableConfig {
    Integer getLoadTimeoutInSeconds();
    void setLoadTimeoutInSeconds(final Integer loadTimeoutInSeconds);
}

public interface AccessibleConfig extends LoadableConfig {
    Boolean getHoverOverAccessorWithJavascript();
    void setHoverOverAccessorWithJavascript(final Boolean hoverOverAccessorWithJavascript);
    Boolean getClickAccessorWithJavascript();
    void setClickAccessorWithJavascript(final Boolean clickAccessorWithJavascript);
}

因此,生成这个最小示例的练习实际上使识别编译器错误的来源变得非常容易。我已经在下面发布了这个问题的答案。我谦虚地接受,事实上我最初并没有发布一个完整的例子。

【问题讨论】:

  • 用一个最小的完整示例来说明这一点怎么样?这里有很多松散的结局。
  • 关于命名的旁注:约定是使用单个字符作为类型参数。只需将其称为 T,而不是 ConfigT。其他任何事情都会让任何有一点经验的 Java 程序员感到困惑。
  • @GhostCat 可以扩展为全大写名称,但仅限于参数较多的特殊情况。 CamelCase 绝对是最糟糕的。
  • 这是骆驼案,因为我被要求在代码审查中这样做。过去我也曾因发布过多代码而没有深入研究确切的问题而受到批评。因此,反对票的推动并不是特别有用。
  • 开车经过?人们已经告诉过你需要做什么。提供minimal reproducible example

标签: java generics


【解决方案1】:

我已经确定了问题所在。具体类需要将自己传递给父类,因为父类是自反通用的。错误消息不是很有帮助,所以我一直在思考父类方法的泛型参数,而不是应用于父类本身的泛型参数。

ConcreteLoadable 的类声明需要改成这样才能消除编译错误:

public class ConcreteLoadable extends AbstractLoadable<ConcreteLoadable> {

    public ConcreteLoadable(final String profileName) {

        AccessibleConfig config = getConfig(ConcreteLoadable.class.getCanonicalName());
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    相关资源
    最近更新 更多