你从一开始就在使用Java吗?你是否还记得java被称作为”Oak”的时期?那时,面向对象仍然是一个热门的话题,使用C++的人们都认为Java没有任何机会,Applets 也只是一件事情。 我敢打赌你肯定不知道以下一半的事情。现在,让我们开始一些Java内部运作的大惊喜。 1. 并没有所谓的检查异常 没错,Java虚拟机(JVM)不知道异常,只有Java语言自己知道. 如今,每个人都同意检查异常是一个错误。正如Bruce Eckel 在Prague的 GeeCON 闭幕词上所说,在Java之后没有其他语言会约定使用检查异常,甚至 Java 8 新的流API都不再包含这些(在lambdas表达式中使用IO 或者JDBC时,是有点痛苦)。 (译者注:Java8 引入了lambads表达式,使用它能够使设计代码更简洁) 使用下面的代码可以证明JVM并不知道这些: 上面的代码不仅能通过编译,而且抛出了异常SQLException,你甚至不需要使用Lombok’s 的注解@SneakyThrows。 (译者注:Lombok是一个使用注解简化Java代码的库) (译者注:如果你在方法中没有声明throws子句,当程序出现异常时Lomok 注解@SneakyThrows 会偷偷的抛出检查异常)点这里获取关于这篇文章的更多细节,或 Stack Overflow。 2. 重载仅返回类型不同的方法 这不能通过编译,不是吗? 是的。Java语言不允许在同一个类中存在"等价覆盖" 的两个方法.不管它们有不同的 throws 子句或是不同的返回类型。 在 Javadoc Class.getMethod(String,Class...)。上面有如下说明: 注意:它在一个类中可能会匹配到多个方法,虽然Java语言禁止在一个类中声明多个签名相同而仅返回类型不同的方法,但是Java虚拟机不会如此。在Java虚拟机中,这种增强 的灵活性被用于实现多样的语言特性。例如,协变返回值类型能通过桥接方法实现;桥接方法和被覆盖的方法将有相同的签名,不同的返回类型。 这很有意义,事实上,下面的语句所发生的几乎就是这样。 查看生成的字节码: 因此,很好理解 T 在字节码中就是一个对象。 这个合成的桥接方法实际上是由编译器生成的,因为Parent.x()的返回类型签名在某些调用位置可能会被期望成 Object。 加入的泛型没有这样的桥接方法就不可能以一种二进制的方式兼容。 因此,改变JVM去支持这种特性只需很少的代价(同样也允许协变性压倒一切负效应)很聪明,不是吗? 你分析过语言的细节和内幕吗?点这里发现更多有趣的细节。 |