關於 Java 你必須知道的 5 件事!

2022-01-25 書圈

熱文導讀 | 點擊標題閱讀

寒門學子:進得去的名校,抹不掉的階層烙印

現在的大學生「大學越上越迷茫 不知道努力方向」

耶魯大學教授給研究生的忠告:沒有人能管你

年薪50萬是什麼樣的工作?

作為Java書呆子,比起實用技能,我們會對介紹Java和JVM的概念細節更感興趣。因此我想推薦LukasEder在jooq.org發表的原創作品給大家。

你是從很早開始就一直使用 Java 嗎?那你還記得它的過去嗎?那時,Java 還叫 Oak,OO 還是一個熱門話題,C++ 的 folk 者認為 Java 是不可能火起來,Java 開發的小應用程式 Applets 還受到關注。

我敢打賭,下面我要介紹的這些事,有一半你都不知道。下面讓我們來深入探索 Java 的神秘之處。

1. 沒有檢查異常這種事情

沒錯!JVM 不會知道這些事情,只有 Java 語句知道。

如今大家都認為檢查異常是個錯誤。正如 Bruce Eckel 在布拉格 GeeCON 閉幕時所說,Java 之後再沒別的語言檢查異常,甚至 Java 8 在新的 Stream 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 語言不允許兩個方法在同一個類中「等效重載」,而忽略其諸如throws自居或返回類型等的潛在的差異。

查看 Class.getMethod(String, Class…) 的 Javadoc。 其中說明如下:

請注意,類中可能有多個匹配方法,因為 Java 語言禁止在一個類聲明具有相同籤名但返回類型不同的多個方法,但 Java 虛擬機並不是如此。虛擬機中增加的靈活性可以用於實現各種語言特徵。例如,可以用橋接方法實現協變參返回; 橋接方法和被重寫的方法將具有相同的籤名但擁有不同的返回類型。

哇哦,有道理。實際上下面的代碼暗藏著很多事情:

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: 1java.lang.String x(); 0 ldc </String><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: 1bridge 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。這很好理解。

合成的橋方法實際是由編譯器生成的,因為 Parent.x() 籤名中的返回類型在實際調用的時候正好是 Object。在沒有這種橋方法的情況下引入泛型將無法在二進位下兼容。因此,改變 JVM 來允許這個特性所帶來的痛苦會更小(副作用是允許協變凌駕於一切之上) 很聰明,不是嗎?

你看過語言內部的細節嗎?不妨看看,在這裡會發現更多很有意思的東西。

3. 所有這些都是二維數組!

class Test { int[][] a() { return new int[0][]; } int[] b() [] { return new int[0][]; } int c() [][] { return new int[0][]; }}

是的,這是真的。即使你的大腦解析器不能立刻理解上面方法的返回類型,但其實他們都是一樣的!類似的還有下面這些代碼片段:

class Test { int[][] a = {{}}; int[] b[] = {{}}; int c[][] = {{}};}

你認為這很瘋狂?想像在上面使用 JSR-308 / Java 8 類型註解 。語法的可能性指數激增!

@Target(ElementType.TYPE_USE)@interface Crazy {}class Test { @Crazy int[][] a1 = {{}}; int @Crazy [][] a2 = {{}}; int[] @Crazy [] a3 = {{}}; @Crazy int[] b1[] = {{}}; int @Crazy [] b2[] = {{}}; int[] b3 @Crazy [] = {{}}; @Crazy int c1[][] = {{}}; int c2 @Crazy [][] = {{}}; int c3[] @Crazy [] = {{}};}

類型註解。看起來很神秘,其實並不難理解。

或者換句話說:

當我做最近一次提交的時候是在我4周的假期之前。

對你來說,上面的內容在你的實際使用中找到了吧。

4. 條件表達式的特殊情況

可能大多數人會認為:

Object o1 = true ? new Integer(1) : new Double(2.0);

是否等價於:

Object o2;if (true)    o2 = new Integer(1);else    o2 = new Double(2.0);

然而,事實並非如此。我們來測試一下就知道了。

System.out.println(o1);System.out.println(o2);

輸出結果:

1.01

由此可見,三目條件運算符會在有需要的情況下,對操作數進行類型提升。注意,是只在有需要時才進行;否則,代碼可能會拋出 NullPointerException 空引用異常:

Integer i = new Integer(1);if (i.equals(1))    i = null;Double d = new Double(2.0);Object o = true ? i : d; // NullPointerException!System.out.println(o);

5. 你還沒搞懂複合賦值運算符

很奇怪嗎?來看看下面這兩行代碼:

i += j;i = i + j;

直觀看來它們等價,是嗎?但可其實它們並不等價!JLS 解釋如下:

E1 op= E2 形式的複合賦值表達式等價於 E1 = (T)((E1) op (E2)),這裡 T 是 E1 的類型,E1 只計算一次。

非常好,我想引用 Peter Lawrey Stack Overflow 上的對這個問題的回答:

使用 *= 或 /= 來進行計算的例子

byte b = 10;b *= 5.7;System.out.println(b); // prints 57

或者

byte b = 100;b /= 2.5;System.out.println(b); // prints 40

或者

char ch = '0';ch *= 1.1;System.out.println(ch); // prints '4'

或者

char ch = 'A';ch *= 1.5;System.out.println(ch); // prints 'a'

現在看到它的作用了嗎?我會在應用程式中對字符串進行乘法計算。因為,你懂的…

結論

一句話總結這篇文章就是:

Java 恰好是一種看起來神秘的語言,其實不然。

*  文章轉載自:https://www.oschina.net/translate/10-things-you-didnt-know-about-java



作者 |  圖文來自網絡、如涉及版權問題,請聯繫我們以便處理。文章內容純屬作者個人觀點,不代表本網觀點。

編輯 | 老貓

讀書吧 | QQ群:481160039

相關焦點

  • 關於 Java 序列化你不知道的 5 件事
    團隊感到陷入僵局,但這只是因為他們不知道關於 Java 序列化的一個重要事實:Java 序列化允許隨著時間的推移而改變類型。當我向他們展示如何自動進行序列化替換後,他們終於按計劃完成了向 HashMap 的轉變。本文是本系列的第一篇文章,這個系列專門揭示關於 Java 平臺的一些有用的小知識 — 這些小知識不易理解,但對於解決 Java 編程挑戰遲早有用。
  • 關於 Java 對象序列化您不知道的 5 件事
    除非對每個持久化的用戶設置運行某種類型的數據轉換實用程序(極其龐大的任務),否則以後似乎只能一直用Hashtable 作為應用程式的存儲格式。團隊感到陷入僵局,但這只是因為他們不知道關於 Java 序列化的一個重要事實:Java 序列化允許隨著時間的推移而改變類型。當我向他們展示如何自動進行序列化替換後,他們終於按計劃完成了向 HashMap 的轉變。
  • 關於 Java 你不知道的十件事
    你在Java發布的時候就開始使用了嗎?還記得那時它叫「Oak」,面向對象也 (Object Oriented, OO )還是個熱門話題,C++ 程式設計師們覺得 Java 完全沒機會成功,Applet的出現也是一件新鮮大事?我打賭下文中至少一半的內容你都不知道。讓我們來看看這些令人驚喜的 Java 細節吧。1.
  • 關於Java你不知道的十件事
    還記得那些被稱為「 Oak」的日子,OO仍然是熱門話題,C ++人士認為Java沒有機會,Applet還是一件事嗎?我敢打賭,您至少不了解以下一半內容。1.沒有被檢查的異常那就對了!JVM不知道任何這樣的事情,只有Java語言知道。
  • 關於 Java 你不知道的 10 件事
    JVM 不會知道這些事情,只有 Java 語句知道。如今大家都認為檢查異常是個錯誤。正如 Bruce Eckel 在布拉格 GeeCON 閉幕時所說,Java 之後再沒別的語言檢查異常,甚至 Java 8 在新的 Stream API 中也不再幹這個事情(如果你的 Lambda 使用 IO 和 JDBC,這其實還是有點痛苦)。如何證實 JVM 並不清楚檢查異常一事?
  • 關於立冬,你必須要知道的10件事!
    關於立冬,你必須要知道的10件事1. 立冬,是我國傳統農曆中24節氣的第19個節氣。一般是11月6日或7日。今年的立冬是11月7日。 5.立冬過後,天明顯黑得更早,防寒保暖也顯得更加重,其次就是要「補一補」;6.冷空氣活動頻繁,明顯降溫後又轉晴,寒暖交替;7.北方立冬習俗典型代表是餃子,而南方立冬大都以肉類為補,如羊肉湯、牛肉、海鮮等等。
  • 日本留學之打工你必須知道的5件事~
    今天就給大家整理一下「留學生在日本打工必須知道的5件事」,以此送給即將要赴日留學以及剛剛來日本想要打工的同學們。一. 但是如果機場沒有辦理權限的話,那麼就要去你在日居住地所屬的入管局去辦理。需要注意的是,如果想打工,資格外活動許可證就必須要辦理。如果沒有這個證件去打工,就屬於「打黑工」,萬一被入管局或者警察查到的話,就會被遣返回回國,你的留學生涯也就被白白斷送了。所以在辦理在留卡的時候一定記得要同時辦理「資格外活動許可證」。二.
  • 關於Java垃圾回收,你必須要知道FullGC是什麼
    作為程式設計師要關注的區域主要有5塊,分別是方法區(Method Area),Java棧(Java stack),本地方法棧(Native Method Stack),堆(Heap),程序計數器(Program Counter Register)。實際jvm在管理內存的時候,比這個分的更細緻,只不過做應用程式開發,我們只需要關注這5塊就可以了。
  • 關於貝賽思,你必須知道的43件事!
    ▲  點擊上方貝賽思BASIS家長幫關注我們去年7月份,我們推送了《關於貝賽思,你必須知道的43件事!》(◀點擊文字,閱讀文章)一年過去,貝校越辦越好,建了新的校區,迎來了國內第二屆畢業生,並取得了不俗的升學成績。
  • 關於4K超高畫質電視 你必須知道的十件事
    14K電視的基礎知識知多少    【中關村在線電視頻道原創】目前在國外很多網站中,我們經常會看到入諸如「關於某某你必須知道的N件事」,類似於這樣的內容。   最近,國外有網站發布了關於4K電視你必須知道的十件事,對現在流行的4K超高畫質電視進行了探討。那麼,國外友人在面對4K電視方面,是否和我們的想法相同又有何不一樣的見解呢?
  • 博大學歷提升 | 關於成人高考你必須知道的4件事
    博大學歷提升 | 關於成人高考你必須知道的4件事專科考:語數英,每科100分,總分450 3、名校錄取分數線比普通院校錄取分數線高名校錄取分數線比普通院校錄取分數線高,以廣東為例,往年華師錄取分數線必須高於120分,但有些普通院校招生名額有空餘,會降分錄取。總的來說,想簡單容易考過的,選文科類專業與普通院校。 三、成考怎麼報名?
  • 關于格蘭菲迪威士忌,這 11 件事你必須知道
    喝威士忌的沒有不知道單一麥芽(Single Malt)的,說起單一麥芽沒有不知道格蘭菲迪(Glenfiddich)的。格蘭菲迪行銷全球 180 個國家,銷量驚人,在全球都有相當高的知名度。不過知道不代表了解,要了解格蘭菲迪,這 11 件事你必須要知道:1、DIY 的釀酒廠 在 1886 年夏天,格蘭菲迪創始人威廉·格蘭特(William Grant)和他的 7 個兒子、2 個女兒和一個石匠手工建造了他家的釀酒廠。
  • 關於做Pitch,創始人必須知道的14件事
    你沒有找到合適的投資人,或者你所在的城市沒有一個成熟的創業環境。4. 你的Pitch 爛透了,你還沒有準備好站在臺上或者隨便在哪裡簡單地講一講你的故事。如果是最後這個原因,那我真的無能為力。建立一家優秀的公司遠比做一個好Pitch更重要,但如果你不知道怎麼講述你的故事,那你可能不了解你的公司最吸引人的地方是什麼。這個問題會對籌資以及其他很多事都造成影響。
  • 關於增強Swing您所不知道的5件事
    在本期的 5 件事 系列 文章中,我將向您介紹 4 個免費開源組件,您可以用來現代化您的 Swing GUI,並圍繞那些您可能還不可了解的 Swing 線程展開討論。  1. Substance  將一個 Java 應用程式和一個本地作業系統整合起來是比較麻煩的,主要是因為 Swing 的組件是人工繪製的。
  • 關於祛痘,你必須知道的5件事!
    所有經驗和教訓,凝結成5點,分享給大家,一定要記在小本本上啊~是你,你會選擇哪一種呢?你的選擇,最終會決定你更傾向於採用哪一種方式對待你的皮膚。認真對待醫生給你開的藥,他們會詳細介紹藥的用法、用量,甚至可以明確地告知你要不要停掉你正在進行的護膚步驟。
  • 《我的世界》關於史萊姆必須要知道的5件事情
    那麼今天卡特曼就總結關於史萊姆你要知道的五件事!NO.1 史萊姆的生成史萊姆分為大、中、小三種形態,如果遭遇連續攻擊,則會分裂成1~4個小史萊姆。史萊姆的會在特定的地區生成,值得注意的是史萊姆生成的Y坐標必須小於40才可以生成哦。如果大家不知道區域塊在什麼位置,有種最簡單的辦法,就是登陸http://chunkbase.com/apps/slime-finder 這個網站,可以直接查找史萊姆的區域塊。
  • 關於聖誕大戰你必須要知道的10件事,讓你做一個有點東西的老球迷
    下面就讓我們一起來看看,關於聖誕大戰的那些必須要知道的10件事吧!兩次參加聖誕大戰的麥迪,一場砍下46分,一場砍下41分,場均43.5分的聖誕大戰得分紀錄一直到今天都無人打破,遙遙領先第二名的傑裡-韋斯特(32.4分)。
  • Java 開發者最困惑的四件事
    讀完本文你會對這些概念有更深入的了解,還能弄清楚一切灰色的東西。在本書中,我們將討論匿名內聯類、多線程、同步和序列化。你也許知道,匿名類可以用接口來創建,也可以通過擴展抽象或具體的類來創建。上例中我先創建了一個接口Football,然後在類的作用域和main()方法內實現了匿名類。Football也可以是抽象類,也可以是與interface並列的頂層類。Football可以是抽象類,請看下面的代碼。
  • 你必須掌握的 21 個 Java 核心技術!
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫51閒來無事,師長一向不(沒)喜(有)歡(錢)湊熱鬧,倒不如趁著這時候覆盤復盤。
  • 帶著孩子必須要做的5件事,你做了幾件
    孩子的三觀,未來發展,跟父母是息息相關的,主要看父母如何去做一個引導,如何去培養孩子,全靠父母接下來的用心程度,沒有一個父母對孩子不上心的,只不過是不知道如何培養,引導孩子,只能心理著急,甚至是做一些自以為的培養,按照之前老一輩的思路來,現在對於孩子的培養,之前的老路有的適合有的不適合,那麼如果你還不知道如何培養孩子,那麼這篇文章一定要好好看一看,帶著孩子必須要做的5件事,你帶孩子多了幾件。