具有通用类型参数的主方法,为什么有效?

35
public static <T extends String> void main(T[] args) {
    System.out.println("Hello World!");
}

我很好奇上面的代码片段是否能够成功编译和运行,结果它确实可以!但是,我也想知道如果将 T extends String 替换为 T extends String & 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中测试过。
  • 您也可以像使用任何其他程序一样使用命令行传递参数。
1个回答

30
这是因为类型参数有一个限定:
<T extends String>                  =>  String

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

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

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

JLS §4.4. 类型变量:

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


4
@Li357 只有第一个边界对被擦除类型起作用。 - Andy Turner
3
有趣的是,在添加了args[0].close();和必要的throws Exception声明后,该程序仍然可以编译且没有任何警告,但在运行时会失败,因为String无法转换为AutoCloseable - wchargin
1
@wchargin:说得好!但我认为你的编译器没有为此发出任何警告并不是太令人惊讶,因为定义一个main方法而不打算将其作为入口点是合法的。(根据我的经验,没有编译器会对类似于public static void main()这样的内容发出警告。)main方法被调用的方式实际上类似于反射,绕过了在运行时未被具体化的静态类型系统的任何方面。 - ruakh
@wchargin,你不需要显式地调用main方法;如果你试图从代码中调用它(传递一个没有实现AutoCloseable接口的参数),那么你将会得到一个“不兼容的边界”编译器错误。 - Oleksandr Pyrohov
你的答案虽然正确,但需要更多的解释。 - Mohammad Dehghan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接