【问题标题】:String gets assigned to a List without a compilation error [duplicate]字符串被分配给列表而没有编译错误[重复]
【发布时间】:2017-01-11 08:33:51
【问题描述】:

据我所知,Java 中泛型的主要目的之一是提供编译时类型安全。如果它被编译,代码将毫无问题地运行。

那为什么要编译下面的代码呢?

public static void main(String[] args) {
    String s = getList();
}

private static <T extends List> T getList() {
    return (T)new ArrayList();
}

它编译得很好。我的类型安全编译在哪里? getList() 方法与 String 类没有任何共同之处。

【问题讨论】:

  • 不,即使使用非原始类型也会编译。
  • @MarkusFischer,我也想过,但是编译器意识到String是final类,不能有任何子类
  • @MarkusFischer,您应该将此评论转换为答案。我认为这正是在这里观察到的问题。 MyClass extends String implements List 可能在编译时是可能的,因为编译器不认为 String 是 final,正如你所说,对于那些通用检查。
  • @AndrewTobilko 编译器只查看 type,而不查看类型是否为 final。 Final 阻止声明子类,但不阻止编译器允许子类的可能性(google Liskov)。换句话说,从(非子类化)类中添加或删除 final 不应该在它们的使用中导致编译失败。类型并没有改变,只是对子类的限制,这是一个实现的东西,而不是一个类型的东西。
  • "如果它被编译,代码将毫无问题地运行。"不会。编译时会收到警告,告诉您它可能不起作用。

标签: java string generics type-safety generic-type-argument


【解决方案1】:

这本身不是类型擦除问题,但几乎相反:当系统知道实际类型时,您在运行时遇到问题,但在编译时不知道。这个编译的原因是List是一个接口。就编译器而言,String 的子类可能实际上实现了该接口,因此编译器认为可能存在有效的运行时情况,其中返回的实际对象是 String,也是 List。编译器不认为 String 是最终的,因此不可能实际创建 List-implementing String 类。

至于为什么在编译过程中不考虑final,Bohemian对这个问题的评论给出了很好的解释。

【讨论】:

  • 不应该至少有一个编译器警告吗?我还没有检查 javac 本身,但是我的 IDE 除了未经检查的强制转换和原始类型之外没有任何警告。我可以举出没有原始类型和没有警告但类型显然不正确的示例。
  • 我同意编译器警告会很好并且对这种情况有意义。我也没有从 javac 或 Eclipse 中看到一个。同样,这归结为编译器调查了多少边缘情况,显然决定不检查这个星座。
猜你喜欢
  • 2018-06-19
  • 1970-01-01
  • 2014-04-26
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
相关资源
最近更新 更多