你是不是一開始就用
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子句和返回類型是不是不同的。
不過等等??聪翵ava文檔中的 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