關於Java你不知道的十件事

2020-12-16 Java從零開始

那麼,您從一開始就一直在使用Java?還記得那些被稱為「 Oak」的日子,OO仍然是熱門話題,C ++人士認為Java沒有機會,Applet還是一件事嗎?

我敢打賭,您至少不了解以下一半內容。

1.沒有被檢查的異常

那就對了!JVM不知道任何這樣的事情,只有Java語言知道。

您是否想要證明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;

}

}

2.您可以使方法重載僅在返回type上有所不同

那不會編譯,對嗎?

class Test {

Object x() { return "abc"; }

String x() { return "123"; }

}

對。Java語言不允許兩個方法 在同一類中「覆蓋等效」,無論它們的throws子句或returntype可能如何不同。

哇,是的,這很有意義。實際上,這幾乎就是您編寫以下內容時發生的情況:

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字節碼。很好理解。

合成橋方法實際上是由編譯器生成的,因為Parent.x()可能期望籤名的返回typeObject在某些調用位置。如果沒有此類橋接方法,則無法以二進位兼容的方式添加泛型。因此,更改JVM以使其具有此功能的痛苦就較小(這也使協變量重載成為副作用……)聰明吧?

您是否熟悉語言細節和內部知識?

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

class Test {

int[][] a() { return new int[0][]; }

int[] b() [] { return new int[0][]; }

int c() [][] { return new int[0][]; }

}

對,是真的。即使您的心理分析器可能無法立即理解上述方法的返回type,它們也是相同的!與以下代碼段相似:

class Test {

int[][] a = {{}};

int[] b[] = {{}};

int c[][] = {{}};

}

你覺得這很瘋狂嗎?

@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.您沒有條件表達式

因此,您認為使用條件表達式時就知道這一切嗎?我告訴你,你沒有。你們大多數人會認為以下兩個片段是等效的:

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.0

1個

是的 有條件的運營商將實現數字式的推廣,如果「被需要」,對一個非常非常非常強的引號的「需要」。因為,您希望該程序拋出一個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.您也沒有得到複合賦值運算符

夠古怪嗎?讓我們考慮以下兩段代碼:

憑直覺,它們應該等效,對嗎?但猜猜怎麼了。他們不是!JLS指定:

形式為E1 op = E2的複合賦值表達式等效於E1 =(T)(((E1)op(E2))),其中T是E1的type,只是E1僅被評估一次。

這是如此的美麗,我想引用彼得Lawrey的回答這個堆棧溢出問題:

這種轉換的一個很好的例子是使用* =或/ =

字節b = 10;

b * = 5.7;

System.out.println(b); //列印57

要麼

字節b = 100;

b / = 2.5;

System.out.println(b); //列印40

要麼

char ch ='0';

ch * = 1.1;

System.out.println(ch); //列印'4'

要麼

char ch ='A';

ch * = 1.5;

System.out.println(ch); //列印'a'

現在,這有多麼難以置信?我將在我的應用程式中將字符轉換/乘法。因為,你知道...

6.隨機整數

現在,這更像是一個難題。尚未閱讀解決方案。看看您是否可以自己找到這個。當我運行以下程序時:

…然後「有時」,我得到以下輸出:

92

221

45

48

236

183

39

193

33

84

7.轉到

這是我的最愛之一。Java有GOTO!輸入...

int goto = 1;

這將導致:

Test.java:44:錯誤:預期<identifier>

int goto = 1;

^

這是因為goto是一個未使用的關鍵字,以防萬一...

但這不是令人興奮的部分。令人興奮的是,你可以真正實現與藤break,continue並標記塊:

向前跳

label: {

// do stuff

if (check) break label;

// do more stuff

}

在字節碼中:

2 iload_1 [檢查]

3 ifeq 6 //向前跳

6 ..

向後跳

label: do {

// do stuff

if (check) continue label;

// do more stuff

break label;

} while(true);

在字節碼中:

2 iload_1 [檢查]

3 ifeq 9

6 goto 2 //向後跳

9 ..

8. Java具有type別名

在其他語言中(例如Ceylon),我們可以非常輕鬆地定義type別名:

interface People => Set<Person>;

People這樣構造的type可以與Set<Person>以下項互換使用:

People? p1 = null;

Set<Person>? p2 = p1;

People? p3 = p2;

在Java中,我們不能在頂級定義type別名。但是我們可以在類或方法的範圍內這樣做。假設我們對Integer,Long等的命名不滿意,我們希望使用更短的名稱:I和L。簡單:

class Test<I extends Integer> {

<L extends Long> void x(I i, L l) {

System.out.println(

i.intValue() + ", " +

l.longValue()

);

}

}

在上述程序中,Integer「別名」 I用於Test類的範圍,而Long「別名」 L用於x()方法的範圍。然後我們可以像上面這樣調用上面的方法:

new Test().x(1, 2L);

當然,這種技術不應被認真對待。在這種情況下,Integer和Long都是最終type,這意味著typeI和L是有效的別名(幾乎,賦值兼容僅是一種方式)。如果我們使用了非最終type(例如Object),那麼我們真的會使用普通的泛型。

這些愚蠢的把戲足夠了。現在換個真正了不起的東西!

9.一些type關係是不確定的!

好吧,現在這將變得非常時髦,因此可以喝杯咖啡併集中精力。請考慮以下兩種type:

// A helper type. You could also just use List

interface Type<T> {}

class C implements Type<Type<? super C>> {}

class D<P> implements Type<Type<? super D<D<P>>>> {}

現在,做typeC和D甚至是什麼意思?

它們有些遞歸,採用遞歸的相似(但略有不同)的方式java.lang.Enum。考慮:

public abstract class Enum<E extends Enum<E>> { ... }

使用以上規範,實際的enum實現僅僅是語法糖:

// This

enum MyEnum {}

// Is really just sugar for this

class MyEnum extends Enum<MyEnum> { ... }

考慮到這一點,讓我們回到兩種type。以下內容可以編譯嗎?

class Test {

Type<? super C> c = new C();

Type<? super D<Byte>> d = new D<Byte>();

}

C是Type <的子type嗎?superC>?

步驟0)C <?: Type <?superC>

步驟1)Type <Type <?super C >> <?:type(繼承)

步驟2)C(檢查通配符?superC)

步 。。。(永遠循環)

接著:

D是Type <的子type嗎?superD <Byte >>?

步驟0)D <Byte> <?: Type <?superC <Byte >>

步驟1)Type <Type <?superD <D <Byte >>>> <?:type<?superD <Byte >>

步驟2)D <Byte> <?: Type <?superD <D <Byte >>>

步驟3)Type <type <?superC <C >>> <?:type<?superC <C >>

步驟4)D <D <Byte >> <?: Type <?superD <D <Byte >>>

步 。。。(永遠擴展)

嘗試在Eclipse中編譯以上代碼,它將崩潰!

10.類型交點

Java具有一個非常獨特的功能,稱為類型交集。您可以聲明一個(通用)類型,它實際上是兩種類型的交集。例如:

class Test<T extends Serializable & Cloneable> {

}

泛型類型參數T,你綁定的類的實例Test必須實現兩個Serializable和Cloneable。例如,String不是可能的界限,而是Date:

// Doesn't compile

Test<String> s = null;

// Compiles

Test<Date> d = null;

Java 8中已重用了此功能,您現在可以在其中將類型轉換為臨時類型的交集。這有什麼用?幾乎沒有,但是如果您想將lambda表達式強制為這種類型,則別無選擇。假設您的方法受到這種瘋狂的類型約束:

<T extends Runnable & Serializable> void execute(T t) {}

您Runnable還Serializable希望這樣做,以防萬一您想在其他地方執行它並通過電線發送它。Lambda和序列化有點古怪。

Lambda可以序列化:

如果lambda表達式的目標類型和捕獲的參數可序列化,則可以對其進行序列化

但是,即使這是真的,他們也不會自動實現Serializable標記器接口。要強制他們使用這種類型,必須強制轉換。但是當你只投給Serializable……

execute((Serializable) (() -> {}));

…然後,lambda將不再可運行。

嗯...

所以…

將其強制轉換為兩種類型:

execute((Runnable & Serializable) (() -> {}));

最後,開發這麼多年我也總結了一套學習Java的資料與面試題,如果你在技術上面想提升自己的話,可以關注我,私信發送領取資料或者在評論區留下自己的聯繫方式,有時間記得幫我點下轉發讓跟多的人看到哦。

相關焦點

  • 關於 Java 序列化你不知道的 5 件事
    Hashtable 和 HashMap 在磁碟上的格式是不相同、不兼容的。除非對每個持久化的用戶設置運行某種類型的數據轉換實用程序(極其龐大的任務),否則以後似乎只能一直用Hashtable 作為應用程式的存儲格式。團隊感到陷入僵局,但這只是因為他們不知道關於 Java 序列化的一個重要事實:Java 序列化允許隨著時間的推移而改變類型。
  • 關於 Java 你不知道的 10 件事
    JVM 不會知道這些事情,只有 Java 語句知道。如今大家都認為檢查異常是個錯誤。正如 Bruce Eckel 在布拉格 GeeCON 閉幕時所說,Java 之後再沒別的語言檢查異常,甚至 Java 8 在新的 Stream API 中也不再幹這個事情(如果你的 Lambda 使用 IO 和 JDBC,這其實還是有點痛苦)。如何證實 JVM 並不清楚檢查異常一事?
  • 你需要知道的關於海洋垃圾的十件事
    你需要知道的關於海洋垃圾的十件事
  • 關於全畫幅微單相機 你可能不知道的十件事
    關於全畫幅微單相機,即便是專業用戶可能也不能夠全面了解,因此今天筆者就來給大家普及全畫幅微單你並不了解的十件事。關於全畫幅微單相機 你可能不知道的十件事一、全畫幅微單多為全新的系統    目前正在銷售的全畫幅微單相機的品牌是佳能、尼康、索尼、松下和徠卡五家
  • 關於《神探夏洛克》你不知道的十件事
    下面放鬆一下心情,一起來回顧一下關於《神夏》的十件趣事,好好期待第四季第二集播出吧,畢竟誰也不知道下一季又要等到什麼時候了。As Sherlock returns to our screens, here are 10 curious things you might not have known about the BBC series:BBC電視劇《神探夏洛克》回歸了,下面是關於這部劇你可能有所不知的
  • 關於愛因斯坦你不知道的十件事
    大多數人都知道, 愛因斯坦是一個著名科學家,他想出了著名公式e = mc2 。但是,有10件事也許你不知道。  Most people know that Albert Einstein was a famous scientist who came up with the formula E=mc2.
  • 關於高潮,你一定不知道的十件事
    中國人對於這一塊的事總是避而不談,所以我們對這塊的內容知之甚少。那麼關於它,有哪些為人所罕知的呢?它對於生物來說又有怎樣的意義呢?要是你用電極刺激這兒,你可能就會得到一場極致的快樂。並且刺激死人的時候也能夠引起脊椎反射。當然,這裡的死人指的是腦死亡但有心跳的人。如果你對一個這樣的人刺激他身體上的某些特定部位,你常常會看到他的手會自己動起來抱在胸前,這是一種叫拉薩路反射(Lazarus reflex)的現象。
  • 關於4K超高畫質電視 你必須知道的十件事
    14K電視的基礎知識知多少    【中關村在線電視頻道原創】目前在國外很多網站中,我們經常會看到入諸如「關於某某你必須知道的N件事」,類似於這樣的內容。   最近,國外有網站發布了關於4K電視你必須知道的十件事,對現在流行的4K超高畫質電視進行了探討。那麼,國外友人在面對4K電視方面,是否和我們的想法相同又有何不一樣的見解呢?
  • 漲姿勢:關於艾菲爾鐵塔你不知道的十件事
    此文為您揭曉艾菲爾鐵塔——巴黎,乃至全法國的心臟——的十件趣事。   1.The Eiffel Tower was originally painted red.   艾菲爾鐵塔最初被漆成紅色。   It appeared in red color in the center of Paris in 1889.
  • 關於「套套」你所不知道的9件事
    當你以正確的方式戴套套的時候,出事的機率是非常低的。但很不幸,這種理想情況通常只出現在實驗室的條件下。在現實世界裡,人們對套套的各種誤用會導致保險套失效。當談到以正確的方法戴套套的時候,你所不知道的東西會傷害你。(如果需要背景閱讀,可以參考安全性愛終極指南。)你所不知道的首先,我們來聊聊關於套套的幾個謬見—這樣的謬見有許多—能妨礙你堅持使用套套。要知道,合理使用套套的第一步是在愛愛之前戴上它。謬見:男人戴上套套就不會有快感。
  • 關於跑鞋你不知道的20件事
    [導讀]  以下是你可能不知道的關於跑鞋的20件事,看看你都知道多少:  1、跑鞋面料的創新技術來源於女性內衣——彈性、柔軟、貼身、支持;  2、跑者該穿中性、穩定性和運動控制兼備的跑鞋,而不是隨便都行。  3、耐克取名自希臘勝利女神,也是40s50s的防空飛彈系統。其前身是鬼冢虎的美國分銷公司。
  • 面對「扣肉」CPU 你必須知道的十件事
    面對「扣肉」CPU 你必須知道的十件事 2006年07月13日 05:17作者:靳勝春編輯:靳勝春   這個月底,備受期待的Conroe處理器即將發布
  • 關於增強Swing您所不知道的5件事
    在本期的 5 件事 系列 文章中,我將向您介紹 4 個免費開源組件,您可以用來現代化您的 Swing GUI,並圍繞那些您可能還不可了解的 Swing 線程展開討論。  1. Substance  將一個 Java 應用程式和一個本地作業系統整合起來是比較麻煩的,主要是因為 Swing 的組件是人工繪製的。
  • 關於魅族Pro 7背部畫屏 這十件事你必須知道!
    原標題:關於魅族Pro 7畫屏 這十件事你必須知道 「雙瞳如小窗 佳景觀歷歷」 ,一首楊柘大師風格的詩句讓魅族Pro 7的品牌格調提升到了新的文學高度,與此同時魅族Pro 7 Plus的售價也達到了4080元的新高,邁出了魅族品牌升級的第一步。不少網友戲稱,魅族Pro 7背部這塊1.9英寸的畫屏至少值1000塊。
  • 關於中國與寮國的關係,你需要知道的幾件事
    原標題:新聞背景:關於中老關係,你需要知道的幾件事應寮國人民革命黨中央委員會總書記、寮人民民主共和國主席本揚邀請,中共中央總書記、國家主席習近平將對寮國進行國事訪問。當前,中老關係正處在歷史最好時期。關於兩國關係,你需要知道以下幾件事。寮國北接中國,兩國山水相連,友好交往源遠流長。
  • 租借嫁衣你必須知道的十件事
    可是,有時好事多磨,由於新娘在婚禮上太過激動或是忙於接待親友,致使妝容、造型出現小狀況,這時,新娘們該如何應付這些突發情況,臨陣不亂呢?租借嫁衣必須知道十件事技巧一 價格租婚紗的價格,根據婚紗的材質和款式有所不同。
  • 關於肯德基你不知道的10件事
    至少,你可以認出上校和他那著名的紅色炸雞桶。最重要的是,你可能已經讀過無數關於這個系列的新聞故事——好的和壞的,正確的和錯誤的。但這裡有一些你可能沒有讀過或聽說過的關於這個快餐業巨頭的事情,會讓你大吃一驚。
  • 夏天去京都旅行必須要做的十件事你知道嗎?
    夏天的京都是最好的季節,雖然因為地處盆地,所以天氣會酷暑炎熱,但有些事也只有到了夏天才能看到體驗到。那麼你知道來到京都一定要做的十件事是什麼嗎?第二件事 在三十三間堂被千手觀音圍繞在120米的本堂內,以千手觀音坐像為中心,排列著1000座千手觀音像,而這千尊佛像面像皆不相同,令人嘆為觀止!但要注意,殿內不可以拍照。
  • 背景資料:關於平昌冬奧 你應該知道的10件事
    關於平昌冬奧會 你應該知道的10件事!  2月9日~25日  第23屆冬奧會將在韓國平昌舉行  平昌在哪兒?  平昌冬奧會獎牌長啥樣?  平昌冬奧都有哪些新項目?  朝韓如何共同入場?  俄羅斯選手如何參賽?
  • 關於耶穌,你不知道的那些事
    你或多或少聽過耶穌的名字,多少也知道關於耶穌的一些事情。今天,就和你聊聊關於耶穌,你不知道的那些事。首先,說說耶穌的出生。耶穌,公元元年出生在以色列國的一個小城市伯利恆。當時以色列在羅馬帝國的統治之下,屬於羅馬的一個行省。