你不知道Java的10件事
你從一開始就在使用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去支援這種特性只需很少的代價(同樣也允許協變性壓倒一切負效應)很聰明,不是嗎?
你分析過語言的細節和內幕嗎?點這裡發現更多有趣的細節。
3. 這些都是二維陣列
這是真的。你可能無法立刻理解上面方法的返回型別,但它們都是一樣的。類似於下面的方法:
你肯定認為這瘋了。想象一下,為上面的方法使用 JSR-308 / Java 8 的型別註解。句法的數量將會激增。
4. 你不明白條件表示式
你認為你在使用條件表示式時明白一切嗎?讓我告訴你吧,你不明白。大多數人都會認為下面兩個程式碼片段是等價的:
真的一樣嗎?
不一樣。我們來驗證一下:
程式的輸出結果為:
1.0 1
沒錯!條件運算子在必要的時候將實現資料型別的提升。下面的語句將會丟擲一個NullPointException。
點這裡獲取更多細節。
5. 你也不明白複合賦值運算子
看下面的程式碼:
乍一看它們應該是等價的,但事實上不是。見 JSL(Java語言規範):
複合賦值表示式 E1 op= E2 與 E1 = (T)((E1) op (E2)) 是等價的,T的型別與E1相同,此外 E1僅計算一次。
這真是太美了,我想引用Peter Lawrey's 關於堆疊溢位問題的回答:
6. 隨機整數
這是一個難題。不要參看解答,你能獨立的解決問題嗎?
執行下面的程式碼:
我有時候會得到如下輸出:
92 221 45 48 236 183 39 193 33 84
這怎麼可能?
答案在這。通過反射覆蓋 JDK's 的 Integercache,然後使用自動裝箱和自動拆箱機制。
執行上面的程式碼,你就可以得到類似的結果了。
7. GOTO
在Java中編寫下列語句:
程式會編譯失敗,錯誤資訊為:
因為goto是一個未使用的關鍵字。
雖然無法在原始碼中直接使用 goto 但是我們可以通過 break,continue 和 標記塊實現。
位元組碼的 goto;
向前跳轉:
它的位元組碼為:
向後跳轉:
它的位元組碼為:
看,是不是出現了goto
8. Java 的型別別名
在其他語言中可以很簡單的使用型別別名,例如Ceylon:
(譯者注:Ceylon是一種新興的計算機程式語言,號稱"Java殺手",它不是Java,而是一種受Java影響的新語言。)
以這種方式構造的 People 可以被 Set<Person> 替換:
在Java中,我們無法在全域性範圍上定義型別別名。由於存在 class 域或方法域,
亦可以定義。考慮兩個我們很不喜歡的命名 Integer 和 Long,為它們取個簡短的名稱 I 和 L:
上面的程式中,在 TestClass 域內 定義 Integer 別名為 I,在 x() 方法域中定義Long
別名為 L。我們可以這樣使用上面的方法:
顯然這種技術不值得重視。在這個例子中,Integer 和 Long 都是 final 型別,也就意味著型別 I 和 L 是有效的別名(那樣的話,程式與型別相容性也就無緣了)。如果我們使用的不是 final 型別,那麼就應該使用泛型。
看夠了這些無聊的把戲了吧!來點厲害的。
9. 一些不可判定的關係型別
讓我們來點咖啡,集中你的注意力,這可是很時髦的東西。考慮下面兩個型別:
現在,你知道 C 和 D 的型別嗎?
它們包含了遞迴,Java、lang、Enum 也是遞迴的。這兩種方式有些相似,但略有不同。
由上面的規範可知,Enum 實際上是由一種糖衣語法實現的。
(譯者注:糖衣語法,指計算機語言中新增的某種語法,這種語法對語言的功能並沒有影響,但是更方便程式設計師使用)
考慮到這一點,讓我們回到先前定義的兩個型別。下列程式碼能編譯成功嗎?
很難回答,Ross Tate 有個答案,不可判定:
嘗試在你的Eclipse中編譯上面的程式碼,崩潰了吧!
看這句話:
有些型別關係在Java中是不可判定的。
如果你有興趣瞭解這個奇怪的Java特性更多細節,就讀一讀 Ross Tate的論文"Taming Wildcards in Java's Type System"(與 Alan Leung 和 Sorin Lerner 合著),或者自己思考關聯子型別多型性與泛型多型性。
10. 交集型別
Java有一個很獨特的特性稱作交集型別(type intersections)。你可以宣告一個泛型,它由兩個型別的交集構成。例如:
要使用繫結的泛型引數 T 去例項化Test 類,這個引數就必須同時實現 Serializable 和 Cloneable。例如 String 不是,而 Date 是:
為了讓你有一個專門的交集型別,這種特性在Java8中得到了重用。如何用它呢?幾乎沒用。但是,當你在 lambda 表示式中強行應用這樣的型別時,就只有此種方法可行。
假設你在方法中使用了這種瘋狂的型別約束:
你需要一個實現了Runnable 和Serializable 的物件。為了讓你可以在某些地方執行它,或是傳送它,
Lambads 可以被序列化:
如果一個lambda 表示式的目標型別和所需引數是可序列化的,那麼這個表示式就能序列化。
即使這是真的,那也不會自動的實現序列化標記介面,所以你必須自己動手。
現在你有一個可序列化的,但是它不能被執行。
所以你必須自己加上:
相關文章
- 你不知道的Java重寫Java
- Java String之你不知道的事Java
- ?你不知道的Java內部類Java
- 【譯】10 個你不知道你需要的 HTML 元素HTML
- 美國二次元手遊,你不知道的三件事二次元
- Java核心(四)你不知道的資料集合Java
- 你必須做到的 3 件事
- 你所不知道的 C# 10新特性C#
- 關於Java序列化你不知道的事Java
- 你所不知道的Java效能優化之String!Java優化
- 10 個你可能不知道的 Android Studio 技巧Android
- 可笑,你竟然不知道 Java 如何生成 UUIDJavaUI
- 零基礎如何學習Java?你要注意的8件事Java
- 你不知道的CSSCSS
- 你不知道的setTimeout()
- 你不知道的 WebSocketWeb
- 你不知道的npmNPM
- 你不知道的MutationRecord
- 入行IT為啥建議首選Java?小白學Java你不知道的理由Java
- 你可能不知道的 10 個 Laravel Eloquent 的隱藏特性Laravel
- 分享 10 個你可能不知道的 Laravel Eloquent 小技巧Laravel
- 10 個你不知道的 PostgreSQL 功能:建立統計資訊SQL
- 對你同樣重要的非技術貼,10件事證明你跟錯了人
- 原型—-《你不知道的js》原型JS
- 你所不知道的cssCSS
- JavaScript之你不知道的thisJavaScript
- [譯] 你不知道的 Node
- 你不知道的那些DOM
- 你不知道的JavaScript(二)JavaScript
- 你不知道的JavaScript(一)JavaScript
- 你所不知道的 POST
- 你不知道的js坑JS
- 你所不知道的 Transformer!ORM
- 你不知道的Python容器Python
- 關於Java你不知道的那些事之Java8新特性[HashMap優化]JavaHashMap優化
- 你不知道的《阿里巴巴Java開發手冊》背後故事阿里Java
- 學習swoole之前,你需要知道的幾件事
- SpringApplication你不知道的那些事!SpringAPP
- 型別—-《你不知道的js》型別JS