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

No compiler error about incompatible casts

抱歉,如果这已经解释过了,但我没有在网络上的任何地方找到类似的线程。

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

所以,代码是:

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 接口的 class 总是实现 B 接口(可能解释了为什么 Idea14 说它没问题),但在我看来,这不能证明这种行为是合理的——因为通常我可以创建实现 A 但不实现 B 的 class。我想在我的代码中进行静态类型化,我不想看到运行时 class 转换异常。

那么,谁错了?

Upd. 加个真实的截图classes(不知道会不会解释更多,跟我描述的一样)

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

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

  1. DataSource<?> get(String name): 调用方需要转换为 数据源实现。
  2. <T extends Datasource> T get(Class<T> dsType, String name)。被调用函数可以在运行时检查或 select returned 类型,例如无论是 return Impl1 还是 Impl2。
  3. <T extends Entity>' Datasource<T> get(String name):这可能是故意的。只要 DatasourceImplementation 不需要知道具体的实体类型,它就可以工作。如果它确实需要知道它,那么 <T extends Entity>' Datasource<T> get(Class<T> entityType, String name) 会更好。

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

您有两个相互独立的接口,并且都具有通用类型。

  1. DatasourceImplementation
  2. 数据源

但是,您拥有 并不意味着这些 bose T 是相等的。事实上,它可以是完全不同的实现(都从实体扩展),其中 none 可以转换为其他类型。

而且你有你的界面

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

你说 get 方法应该 return 实现数据源的东西。然而,这个 T 完全独立于其他两个 T。事实上,编译器应该抱怨您将数据源用作原始类型。

你是说 <T extends Entity> Datasource<T> get(String name); 相反?

但是,由于从 Datasource 到 DatasourceImplementation 没有任何关系,因此这两种类型相互独立,就像您拥有 java.lang.Stringjava.lang.Number 一样。尝试将数字分配给声明为 String 类型的引用,反之亦然,也会导致编译器错误。 因此,编译器报错似乎完全没问题。

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

塞巴斯蒂安