你是不是一开始就用
Java来编程的呢?还记得当年它还被称为"Oak",OO还是热门的话题,C++的用户觉得Java没有前景,applets还只是个小玩意,菊花也还是一种花的时候吗?
我敢打赌下面至少有一半是你不清楚的。这周我们来看一下跟Java的内部实现相关的一些神奇的事情。
1. 其实根本没有受检查异常这回事
没错!JVM压根儿就不知道有这个东西,它只存在于Java语言里。
如今大家都承认受检查异常就是个错误。正如Bruce Eckel最近在布拉格的的GeeCON会议上所说的,除了Java外没有别的语言会使用受检查异常这种东西,即使是Java 8的新的Streams API中也不再使用这一异常了(不然当你的lambda表达式中用到IO或者JDBC的话就得痛苦死了)。
如何能证实JVM确实不知道这个异常?看下下面这段代码:
public class Test { // No throws clause here public static void main(String[] args) { doThrow(new SQLException()); } static void doThrow(Exception e) { Test.<RuntimeException> doThrow0(e); } @SuppressWarnings("unchecked") static <E extends Exception> void doThrow0(Exception e) throws E { throw (E) e; } } |
这不仅能通过编译,而且也的确会抛出SQLException异常,并且完全不需要用到Lombok的@SneakyThrows注解。
更进一步的分析可以看下这篇
文章,或者Stack Overflow上的这个问题。
2. 不同的返回类型也可以进行方法重载
这个应该是编译不了的吧?
class Test {
Object x() { return "abc"; }
String x() { return "123"; }
}
是的。Java语言并不允许同一个类中出现两个重写等价("override-equivalent")的方法,不管它们的throws子句和返回类型是不是不同的。
不过等等。看下Java文档中的 Class.getMethod(String, Class...)是怎么说的。里面写道:
尽管Java语言不允许一个类中的多个相同签名的方法返回不同的类型,但是JVM并不禁止,所以一个类中可能会存在多个相同签名的方法。这添加了虚拟机的灵活性,可以用来实现许多语言特性。比如说,可以通过bridge方法来实现协变返回(covariant return,即虚方法可以返回子类而不一定得是基类),bridge方法和被重写的方法拥有相同的签名,但却返回不同的类型。
哇,这倒有点意思。事实上,下面这段代码就会触发这种情况:
abstract class Parent<T> {
abstract T x();
}
class Child extends Parent<String> {
@Override
String x() { return "abc"; }
}
看一下Child类所生成的字节码:
// Method descriptor #15 ()Ljava/lang/String; // Stack: 1, Locals: 1 java.lang.String x(); 0 ldc <String "abc"> [16] 2 areturn Line numbers: [pc: 0, line: 7] Local variable table: [pc: 0, pc: 3] local: this index: 0 type: Child // Method descriptor #18 ()Ljava/lang/Object; // Stack: 1, Locals: 1 bridge synthetic java.lang.Object x(); 0 aload_0 [this] 1 invokevirtual Child.x() : java.lang.String [19] 4 areturn Line numbers: [pc: 0, line: 1 |
在字节码里T其实就是Object而已。这理解起来就容易多了。
synthetic bridge方法是由编译器生成的,因为在特定的调用点Parent.x()签名的返回类型应当是Object类型。如果使用了泛型却没有这个bridge方法的话,代码的二进制形式就无法兼容了。因此,修改JVM以支持这个特性貌似更容易一些(这顺便还实现了协变返回),看起来还挺不错 的吧?
你有深入了解过Java语言的规范和内部实现吗?这里有许多很有意思的东西。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters