关于不兼容的强制转换没有编译器错误

时间:2015-01-26 08:38:32

标签: java generics java-7 classcastexception

很抱歉,如果已经解释过,但我在网站的任何地方都找不到类似的主题。

今天我在IDE中打开了一个项目类并看到了一个错误(红色下划线),虽然项目编译成功。

所以,代码是:

public interface DatasourceImplementation<T extends Entity> {
     ....
}

public interface Datasource<T extends Entity> {
     ....
}


public interface DsContext {
    @Nullable
    <T extends Datasource> T get(String name);
}

现在我们将这种方法称为:

DatasourceImplementation dsImpl = getDsContext().get("dsName");

Idea13给了我错误(不兼容的类型) - 我认为这是正确的。

Idea14在此处未显示任何错误。

JDK编译它没有错误 - 这很难过。

必须说,在我们的A接口的项目实现类中总是实现B接口(可能解释为什么Idea14说它没关系),但在我看来这不能证明这种行为是正确的 - 因为通常我可以创建实现的类A并没有实现B.我想在我的代码中使用静态典型化,我不希望看到运行时类转换异常。

那么,谁在这里错了?

更新。添加真实课程的截图(不确定它会解释更多内容,它与我描述的相同)

enter image description here

2 个答案:

答案 0 :(得分:3)

JDK是正确的。声明承诺返回任何数据源,如果它不匹配则只会出现运行时错误。编译器可能会显示一些严重警告,但应编译它。您的代码段的原始开发人员可能打算避免在每次调用时进行显式转换。

根据意图如何修复它的不同方法:

  1. DataSource<?> get(String name):来电者需要施展 DatasourceImplementation。
  2. <T extends Datasource> T get(Class<T> dsType, String name)。被调用的函数可以在运行时检查或选择返回的类型,例如要返回Impl1或Impl2。
  3. <T extends Entity>' Datasource<T> get(String name):这可能是有意的。只要DatasourceImplementation不需要知道具体的实体类型,就可以正常工作。如果它确实需要知道它,那么<T extends Entity>' Datasource<T> get(Class<T> entityType, String name)会更好。

答案 1 :(得分:0)

乍一看,您的代码/问题似乎有点奇怪。

您有两个独立的接口,并且都具有泛型类型。

  1. DatasourceImplementation&lt; T extends Entity&gt;和
  2. 数据源&lt; T扩展实体&gt;
  3. 但是你有&lt; T扩展实体&gt;并不意味着这些b的T是相等的。实际上,它可以是完全不同的实现(都从实体扩展),其中没有可以转换为其他类型。

    此外,您有自己的界面

    public interface DsContext {
      @Nullable
      <T extends Datasource> T get(String name);
    }
    

    你说get-method应该返回实现Datasource的东西。然而,这个T完全独立于另一个T。事实上,编译器应该抱怨您将数据源用作原始类型。

    您的意思是<T extends Entity> Datasource<T> get(String name); 代替?

    但是,由于数据源与DatasourceImplementation没有关系,因此这两种类型彼此独立,与java.lang.String一个java.lang.Number相同。尝试将数字分配给声明为String类型的引用,反之亦然也会导致编译器错误。 因此编译器报告错误似乎完全正常。

    代码片段是否遗漏了重要的东西(继承)? 此外,编译器在所有情况下实际上都运行了吗?

    塞巴斯蒂安