1.所有類繼承Object
Java 中的所有類都隱式繼承該類Object
。
我們將在 Java Core 任務中分析繼承是什麼以及它在 Java 中是如何工作的。現在,我們將考慮由此得出的一個簡單事實:
任何類的對像都可以分配給Object
變量。例子:
代碼 | 筆記 |
---|---|
|
變量存儲對對象o 的引用Scanner |
|
變量存儲對對象o 的引用String |
|
變量存儲對對象o 的引用Integer |
|
變量存儲對對象o 的引用String |
這是好消息結束的地方。編譯器不會跟踪保存在變量中的對象的原始類型Object
,因此除了類的方法之外,您將無法 調用保存的對象的Object
方法。
如果你需要調用與對象的原始類型相關聯的方法,那麼你需要先將對它的引用保存在正確類型的變量中,然後調用該變量的方法:
代碼 | 筆記 |
---|---|
|
該程序將無法編譯。該類Object 沒有nextInt() 方法。 |
|
這會起作用。這裡我們使用類型轉換運算符 將對對象 的引用保存 Scanner 在變量中。 Scanner |
您不能直接將Object
變量分配給 Scanner 變量,即使該Object
變量存儲了對對象的引用Scanner
。但是如果你使用你已經知道的類型轉換運算符,你就可以做到這一點。這是它的一般外觀:
Type name1 = (Type) name2;
其中name1
是變量名Type
,是存儲對象引用的變量name2
名。Object
Type
類型轉換
如果變量的類型和對象的類型不匹配,則會ClassCastException
拋出 a 。例子:
代碼 | 筆記 |
---|---|
|
運行時會報錯:這裡會拋出 a ClassCastException |
在 Java 中有一種方法可以避免這種錯誤:我們通過檢查存儲在變量中的對象的類型來做到這一點:
name instanceof Type
運算instanceof
符檢查name
變量是否為Type
對象。
例如,讓我們在不同對象的數組中查找一個字符串:
代碼 | 筆記 |
---|---|
|
自動裝箱會將這些值分別轉換為Integer 、String 和Double 。遍歷對像數組 如果對像是 a String 將其保存到 String 變量在屏幕上顯示變量。 |
2. 為什麼會出現泛型——集合
讓我們回到集合。
Java 開發人員一創建該類ArrayList
,就希望它具有通用性,以便它可以存儲任何類型的對象。所以他們使用 s 的數組Object
來存儲元素。
這種方法的優勢在於您可以將任何類型的對象添加到集合中。
當然,也有幾個弱點。
缺點 1。
從集合中檢索元素時,總是需要編寫類型轉換運算符:
代碼 | 筆記 |
---|---|
|
創建一個集合來存儲對Object 對象的引用用數字填充集合 10 , 20 , ... 100 ; 對集合的元素求和 Typecasting 是必要的 |
缺點2。
不能保證集合包含特定類型的元素
代碼 | 筆記 |
---|---|
|
創建一個集合來存儲對Object 對象的引用我們用表示為對象的數字填充集合 Double :0.0 , 2.5 , 5.0 , ...對集合的元素求和 會出現錯誤:a Double cannot be cast to anInteger |
數據可以放在任何地方的集合中:
- 用另一種方法
- 在另一個程序中
- 從一個文件
- 通過網絡
缺點3。
集合中的數據可能會被意外更改。
您可以將充滿數據的集合傳遞給某種方法。該方法由不同的程序員編寫,將其數據添加到您的集合中。
集合的名稱並沒有明確指出其中可以存儲哪些類型的數據。即使你給你的變量一個明確的名字,對它的引用也可以傳遞給一打方法,而這些方法肯定不會知道變量的原始名稱。
3.泛型
在 Java 中,所有這些問題都被這個叫做泛型的很酷的東西消除了。
在 Java 中,泛型意味著向類型添加類型參數的能力。結果是一個複雜的複合類型。這種複合類型的一般觀點是這樣的:
ClassName<TypeParameter>
這是一個通用類。並且它可以在您通常使用類的任何地方使用。
代碼 | 描述 |
---|---|
|
創建變量 |
|
創建對象 |
|
創建數組 |
Integer
這樣的集合中只能存儲變量:
代碼 | 描述 |
---|---|
|
ArrayList Integer 帶元素的集合這是允許的 這 也可以
自動裝箱
但這是不允許的:編譯錯誤 |
在 Java Collections 探索中,您將學習如何使用類型參數創建您自己的類。現在,我們將看看如何使用它們以及它們是如何工作的。
4. 泛型如何工作
實際上,泛型非常原始。
編譯器只是簡單地將泛型類型替換為普通類型。但是當使用泛型類型的方法時,編譯器會添加一個類型轉換運算符來將參數轉換為類型參數:
代碼 | 編譯器做什麼 |
---|---|
|
|
|
|
|
|
|
|
假設我們有一個對整數集合中的數字求和的方法:
代碼 | 編譯器做什麼 |
---|---|
|
|
換句話說,泛型是一種語法糖,就像自動裝箱一樣,但更多一點。通過自動裝箱,編譯器添加了將 an 轉換int
為 an 的方法Integer
,反之亦然,對於泛型,它添加了類型轉換運算符。
在編譯器編譯帶有類型參數的泛型類之後,它們只是簡單地轉換為普通類和類型轉換運算符。有關傳遞給泛型類型變量的類型參數的信息將丟失。這種效果也稱為類型擦除。
有時編寫泛型類(帶有類型參數的類)的程序員確實需要有關作為參數傳遞的類型的信息。在 Java Collections 任務中,您將學習如何處理這個問題以及它需要做什麼。
5. 關於泛型的一些事實
這裡有一些關於泛型的更有趣的事實。
類可以有多個類型參數。它看起來像這樣:
ClassName<TypeParameter1, TypeParameter2, TypeParameter3>
其實,這並不奇怪。編譯器可以在任何地方添加一個運算符以轉換為一種類型,它可以添加多個類型轉換運算符。
例子:
代碼 | 筆記 |
---|---|
|
該put 方法的第一個參數是Integer ,第二個是String |
泛型類型也可以用作參數。它看起來像這樣:
ClassName<TypeParameter<TypeParameterParameter>>
假設我們要創建一個列表來存儲字符串列表。在這種情況下,我們會得到這樣的東西:
// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");
// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");
// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
泛型類型(帶有類型參數的類型)也可以用作數組類型。它看起來像這樣:
ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];
這裡沒有什麼神奇的事情發生:尖括號只是表示類型名稱:
代碼 | 非通用對應物 |
---|---|
|
|
|
|
|
|
GO TO FULL VERSION