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

Java 关于不兼容强制转换没有编译器错误,java,generics,java-7,classcastexception,Java,Generics,Java 7,Classcastexception,很抱歉,如果已经解释过了,但我在web上的任何地方都找不到类似的线程 今天我在IDE中打开了一个项目类,看到了一个错误(红色下划线),尽管项目编译成功 因此,代码是: public interface DatasourceImplementation<T extends Entity> { .... } public interface Datasource<T extends Entity> { .... } public interface

很抱歉,如果已经解释过了,但我在web上的任何地方都找不到类似的线程

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

因此,代码是:

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

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


public interface DsContext {
    @Nullable
    <T extends Datasource> T get(String name);
}
Idea13给了我错误(不兼容的类型)-我认为这是正确的

Idea14在此不显示任何错误

JDK编译它时没有出现错误——这很令人遗憾

必须指出的是,在我们的项目实现中,A接口的类始终实现B接口(可能解释了Idea14为什么说可以),但在我看来,这并不能证明这种行为是正确的——因为通常我可以创建实现A而不实现B的类。我希望在代码中使用静态类型化,我不想看到运行时类强制转换异常

那么,谁错了

Upd.添加一个包含真实类的屏幕截图(不确定它是否能解释更多内容,与我描述的相同)


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

根据不同的目的,有不同的修复方法:

  • 数据源get(字符串名)
    :调用方需要强制转换到 数据源实现
  • T get(类数据类型,字符串名称)
    。被调用函数可以在运行时检查或选择返回的类型,例如,是否返回Impl1或Impl2
  • 数据源get(字符串名):这可能是有意的。只要DatasourceImplementation不需要知道具体的实体类型,它就可以工作。如果它确实需要知道它,那么数据源get(Class entityType,String name)会更好
    乍一看,您的代码/问题似乎有点奇怪

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

  • 数据源实现和
  • 数据源
  • 然而,你有,并不意味着这些玻色T是相等的。事实上,它可以是完全不同的实现(都是从实体扩展的),其中没有一个可以转换为其他类型

    此外,您还有自己的界面

    public interface DsContext {
      @Nullable
      <T extends Datasource> T get(String name);
    }
    
    公共接口DsContext{ @可空 T get(字符串名); } 您说get方法应该返回实现Datasource的内容。然而,这个T完全独立于另一个T。事实上,编译器应该抱怨您将数据源用作原始类型

    你的意思是
    datasourceget(字符串名)
    相反

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

    代码片段是否遗漏了任何重要内容(继承)? 此外,编译器是否在所有情况下都实际运行


    Sebastian

    这确实很有趣,我们能看到一个完整的简化程序吗?@RichardTingle我添加了这4个简化类的屏幕截图-够了吗?将代码作为文本发布。第一个想法是:您在
    get()
    方法中使用了原始类型的数据源。我们可以看到您实际获取它的行吗?同意这可能是不正确的,但为什么返回类型
    而不仅仅是
    数据源
    ?更可能正确地使用它进行编译,而且很可能这就是您实际的意思。或者在DsContext类上声明
    作为类型参数,而不是
    get
    方法,并将其作为返回类型。例如,
    public DsContext(){…}public T get(){…}
    我理解你的意思,但听起来使用(X是接口)可以避免在X和Y接口之间进行任何类强制转换。这很奇怪,你不觉得吗?
    tf(){return(t)new Integer(1);}
    :编译器只会在f()内显示警告,而不会在调用f()时显示警告。这种返回类型不依赖于任何输入参数的方法确实是一个丑陋的漏洞。请参阅一个丑陋的应用程序。好的,我编写了一些测试,通过这些测试,您可以进行任何您想要的强制转换,因为它们是可能的。看来Idea13是错的(回答了我的问题)。它应该只是将代码标记为不安全的。
    public interface DsContext {
      @Nullable
      <T extends Datasource> T get(String name);
    }