【问题标题】:Main method with generic parameter; why does it work?带有泛型参数的主方法;为什么它起作用?
【发布时间】:2018-12-23 09:57:52
【问题描述】:
public static <T extends String> void main(T[] args) {
    System.out.println("Hello World!");
}

我很想知道上面的 sn-p 代码是否会成功编译和运行,并且确实如此!但是,我也想知道如果T extends String 被替换为T extends String &amp; AutoClosable 会发生什么; String 没有实现AutoClosable,所以没想到这个会运行成功,结果还是成功了!

public static <T extends String & AutoCloseable> void main(T[] args) {
    System.out.println("This still works!");
}

所以我的问题是,为什么这仍然可以成功运行?

注意事项

  • 我正在使用 Java 10.0.1 对此进行测试
  • Intellij 不能很好地使用此方法,因为它不将其视为程序的入口点;我没有用其他 IDE 测试过。
  • 您还可以像使用任何其他程序一样使用命令行传递参数。

【问题讨论】:

    标签: java generics main type-inference


    【解决方案1】:

    这是因为类型参数有一个界限:

    <T extends String>                  =>  String
    
    <T extends String & AutoCloseable>  =>  String & AutoCloseable
    

    在这两种情况下,擦除后的字节码与常规的main 声明相同:

    public static main([Ljava/lang/String;)V
    

    JLS §4.4. Type Variables:

    绑定中类型的顺序仅在 擦除时才有意义 类型变量的类型由其边界中的第一个类型确定,并且 一个类类型或类型变量只能出现在第一个 位置。

    【讨论】:

    • @Li357 只有第一个边界有助于擦除类型。
    • 有趣的是,在添加args[0].close(); 和必要的throws Exception 声明后,程序仍然编译没有任何警告,并且在运行时失败,因为String 不能转换为AutoCloseable
    • @wchargin:好点!但我不认为你的编译器没有为此发出任何警告令人惊讶,因为定义一个甚至不打算作为入口点的main 方法是合法的。 (根据我的经验,没有编译器会针对 public static void main() 之类的内容发出警告。)main 的调用方式实际上类似于反射,绕过了运行时未具体化的静态类型系统的任何方面。
    • @wchargin 您没有显式调用main 方法;如果您尝试从代码中执行此操作(传递未实现AutoCloseable 接口的参数),那么您将收到incompatible bounds 编译器错误。
    • 您的答案虽然正确,但需要更多解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多