你好!您已經非常熟悉原始類型,並且經常使用它們。 程式設計中的原語,特別是 Java 中的原語,有很多優點:它們佔用很少的內存,從而提高了程式的效率,並且被明確地劃分為值的範圍。然而,在學習Java的過程中,我們不只一次重複著,就像一句口頭禪,「在Java中一切皆物件」。但原語是對這些話的直接反駁。它們不是物體。那麼「一切皆對象」的原則是錯誤的嗎?並不真地。在 Java 中,每個基本型別都有它的孿生兄弟,即包裝類別(
包裝類別物件的建立就像任何其他物件一樣:
Wrapper
)。什麼是包裝紙? 包裝器是一個特殊的類,它在其內部儲存原語的值。 但由於這是一個類,它可以創建自己的實例。它們將在內部儲存必要的原始值,同時是真實的物件。包裝類別的名稱與相應基元的名稱非常相似,或完全一致。因此,記住它們會很容易。
原始資料型別的包裝類 | |
---|---|
原始資料類型 | 包裝類 |
整數 | 整數 |
短的 | 短的 |
長的 | 長的 |
位元組 | 位元組 |
漂浮 | 漂浮 |
雙倍的 | 雙倍的 |
字元 | 特點 |
布林值 | 布林值 |
public static void main(String[] args) {
Integer i = new Integer(682);
Double d = new Double(2.33);
Boolean b = new Boolean(false);
}
包裝類別可讓您減輕原始類型的缺點。最明顯的一點是原語沒有方法。例如,它們沒有 method toString()
,因此您無法將數字轉換int
為字串。但有了包裝類Integer
就很容易了。
public static void main(String[] args) {
Integer i = new Integer(432);
String s = i.toString();
}
反向轉換也會遇到困難。假設我們有一個我們確定包含數字的字串。然而,在基本類型的情況下,int
我們將無法從字串中獲取該數字並將其實際轉換為數字。但多虧了包裝類,我們現在有了這個機會。
public static void main(String[] args) {
String s = "1166628";
Integer i = Integer.parseInt(s);
System.out.println(i);
}
輸出: 1166628 我們已成功從字串中檢索到數字並將其指派給引用變數Integer i
。順便說一下,關於連結。您已經知道參數以不同的方式傳遞給方法:基元按值傳遞,物件按參考傳遞。您可以在建立方法時使用這些知識:例如,如果您的方法適用於小數,但您需要透過引用傳遞的邏輯,則可以將參數傳遞給方法而Double/Float
不是double/float
. 另外,除了方法之外,包裝類別還有靜態字段,使用起來非常方便。例如,假設您現在面臨一項任務:將最大可能的數字列印到控制台 int
,然後列印最小可能的數字。 這項任務似乎很簡單,但如果沒有谷歌,你仍然很難完成它。包裝類可以輕鬆讓您解決以下「日常問題」:
public class Main {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
}
}
這些領域可以讓你不會從更嚴肅的任務中分心。更不用說在列印數字2147483647(這正是 MAX_VALUE)的過程中,輸入錯誤也就不足為奇了:) 另外,在之前的一講中,我們已經提請注意這樣一個事實:包裝類別的物件是不可變的(Immutable)。
public static void main(String[] args) {
Integer a = new Integer(0);
Integer b = new Integer(0);
b = a;
a = 1;
System.out.println(b);
}
輸出: 0引用 最初指向的物件а
沒有改變其狀態,否則值b
也會改變。與 一樣String
,不是更改包裝器物件的狀態,而是在記憶體中建立一個全新的物件。為什麼 Java 的創建者最終決定在該語言中保留原始類型?既然一切都應該是對象,而且我們已經有了可以用來表達原語表達的一切的包裝類,為什麼不把它們留在語言中並刪除原語呢?答案很簡單——性能。原始類型之所以被稱為原始類型,是因為它們缺乏物件的許多「重」特徵。是的,一個物件有很多方便的方法,但你並不總是需要它們。有時您只需要數字 33 或 2.62 或true
/的值false
。在物件的所有好處都無關緊要且程式不需要運行的情況下,基元會做得更好。
自動裝箱/自動拆箱
Java中原語及其包裝類別的特性之一是自動裝箱/自動拆箱, 讓我們來理解這個概念。正如您和我之前已經了解到的,Java 是一種物件導向的語言。這意味著所有用Java編寫的程式都是由物件組成的。基元不是對象。但是,可以為包裝類別變數指派基本類型的值。這個過程稱為自動裝箱。以同樣的方式,可以將原始類型的變數指派給包裝類別的物件。這個過程稱為自動拆箱。例如:public class Main {
public static void main(String[] args) {
int x = 7;
Integer y = 111;
x = y; // auto unpacking
y = x * 123; // autopacking
}
}
在第 5 行,我們將 y 的值賦給基元 x,y 是包裝類別的物件Integer
。正如您所看到的,不需要執行任何其他操作:編譯器知道這一點,int
事實上Integer
,是同一件事。這是自動拆包。第 6 行中的自動裝箱也發生了同樣的事情:物件 y 很容易被指派基元的值 (x*123)。這是自動打包的範例。這就是為什麼添加“自動”一詞的原因:將原始引用分配給其包裝類別的物件(反之亦然),您不需要執行任何操作,一切都會自動發生。方便吧?:) 自動打包/自動解包的另一個很大的便利體現在方法的操作上。事實上,方法參數也受到自動打包和自動解包的影響。並且,例如,如果其中一個將兩個物件作為輸入Integer
,我們可以輕鬆地向那裡傳遞普通基元int
!
public class Main {
public static void main(String[] args) {
printNumber(7);//regular int, even without a variable
}
public static void printNumber(Integer i) {
System.out.println("You entered a number" + i);
}
}
輸出: 您輸入了數字 7。 反之亦然:
public class Main {
public static void main(String[] args) {
printNumber(new Integer(632));
}
public static void printNumber(int i) {
System.out.println("You entered a number" + i);
}
}
要記住的重要一點:自動裝箱和拆箱不適用於陣列!
public class Main {
public static void main(String[] args) {
int[] i = {1,2,3,4,5};
printArray(i);//error, won't compile!
}
public static void printArray(Integer[] arr) {
System.out.println(Arrays.toString(arr));
}
}
嘗試將基元數組傳遞給以物件數組作為輸入的方法將導致編譯錯誤。最後,我們再次簡單比較一下原語和包裝 原語:
- 有性能優勢
- 它們讓你不違反「一切皆對象」的原則,這樣數字、符號和布林值true/false就不會脫離這個概念
- 透過提供方便的方法和欄位來擴展使用這些值的能力
- 當某些方法只能與物件一起使用時是必要的
GO TO FULL VERSION