在本文中,我們將了解 Java 中稱為自動裝箱/拆箱的功能。自動裝箱和拆箱是將原始類型轉換為物件類型的功能,反之亦然。 整個過程由Java執行環境(JRE)自動執行。但在實現這個功能時你應該小心,因為...... 它會影響程式的效能。
表 1:帶有比較運算子的基本類型和等效包裝類別 自動裝箱和拆箱可以與比較運算子一起使用。以下程式碼片段說明了這是如何發生的: 清單 3:顯示使用比較運算子進行自動裝箱和拆箱的範例程式碼
介紹
int
在 JDK 1.5 以下的版本中,將、char
、float
、 等原始資料類型轉換double
為它們的包裝類別 Integer、Character、Float、Double並不容易。從 JDK 5 開始,自動實作將原始類型轉換為等效物件的功能。此屬性稱為自動裝箱。相反的過程分別是拆箱,即 將物件轉換為其對應的原始類型的過程。自動裝箱和拆箱的範例程式碼如下:
Integer integer = 9;
拆箱
int in = 0;
in = new Integer(9);
什麼時候使用自動裝箱和拆箱? Java 編譯器在下列條件下使用自動裝箱:
- 當基本類型的值作為方法參數傳遞給方法時,需要對應包裝類別的物件。
- 當將原始類型的值指派給對應包裝類別的變數。
public int sumEvenNumbers(List<Integer> intList ) {
int sum = 0;
for (Integer i: intList )
if ( i % 2 == 0 )
sum += i;
return sum;
}
在 jdk 1.5 之前,上述程式碼會導致編譯錯誤,因為餘數運算子 % 和一元加 += 無法套用於包裝類別。但在 jdk 1.5 以上版本中,這段程式碼編譯沒有錯誤,將 Integer 轉換為int
. Java 編譯器在下列條件下使用拆箱:
- 當物件作為參數傳遞給需要對應基本類型的方法。
- 當一個物件被指派給對應原始類型的變數。
import java.util.ArrayList;
import java.util.List;
public class UnboxingCheck {
public static void main(String[] args) {
Integer in = new Integer(-8);
// 1. Распаковка через вызов метода
int absVal = absoluteValue(in);
System.out.println("absolute value of " + in + " = " + absVal);
List<Double> doubleList = new ArrayList<Double>();
// Автоупаковка через вызов метода
doubleList.add(3.1416);
// 2. Распаковка через присвоение
double phi = doubleList.get(0);
System.out.println("phi = " + phi);
}
public static int absoluteValue(int i) {
return (i < 0) ? -i : i;
}
}
自動裝箱和拆箱允許開發人員編寫易於閱讀和理解的程式碼。下表顯示了原始資料類型及其相應的包裝物件。
原始型 | 外殼類 |
---|---|
布林值 | 布林值 |
位元組 | 位元組 |
字元 | 特點 |
漂浮 | 漂浮 |
整數 | 整數 |
長的 | 長的 |
短的 | 短的 |
public class BoxedComparator {
public static void main(String[] args) {
Integer in = new Integer(25);
if (in < 35)
System.out.println("Value of int = " + in);
}
}
方法重載時的自動打包和解包 方法重載時的自動打包和解包依照下列規則進行:
- 當需要在擴展和封裝之間進行選擇時,擴展會「擊敗」封裝;擴展是更好的選擇。
public class WideBoxed {
public class WideBoxed {
static void methodWide(int i) {
System.out.println("int");
}
static void methodWide( Integer i ) {
System.out.println("Integer");
}
public static void main(String[] args) {
short shVal = 25;
methodWide(shVal);
}
}
}
程式輸出類型int
- 擴展勝過可變數量的參數 在需要在擴展和可變數量的參數之間進行選擇的情況下,擴展是更可取的。
public class WideVarArgs {
static void methodWideVar(int i1, int i2) {
System.out.println("int int");
}
static void methodWideVar(Integer... i) {
System.out.println("Integers");
}
public static void main( String[] args) {
short shVal1 = 25;
short shVal2 = 35;
methodWideVar( shVal1, shVal2);
}
}
- 打包優於可變數量的參數 在需要在打包和可變數量的參數之間進行選擇的情況下,打包是更可取的。
public class BoxVarargs {
static void methodBoxVar(Integer in) {
System.out.println("Integer");
}
static void methodBoxVar(Integer... i) {
System.out.println("Integers");
}
public static void main(String[] args) {
int intVal1 = 25;
methodBoxVar(intVal1);
}
}
使用自動打包時應記住以下事項: 眾所周知,每個好的功能都有一個缺點。汽車包裝在這方面也不例外。開發人員在使用此功能時應牢記的一些重要注意事項:
- 將物件與「
==
」運算子進行比較可能會令人困惑,因為它可以應用於基本類型和物件。當此運算子應用於物件時,它實際上會比較物件的引用,而不是物件本身。
public class Comparator {
public static void main(String[] args) {
Integer istInt = new Integer(1);
Integer secondInt = new Integer(1);
if (istInt == secondInt) {
System.out.println("both one are equal");
} else {
System.out.println("Both one are not equal");
}
}
}
- 將物件和原始類型與相等和關係運算子混合。如果我們將原始類型與物件進行比較,則該物件將被拆箱,
NullPointerException
如果該物件null
. - 對象緩存。該方法
valueOf()
創建一個它緩存的原始物件的容器。由於值的快取範圍為 -128 到 127(含),因此這些快取物件的行為可能有所不同。 - 性能下降。自動裝箱或拆箱會降低應用程式效能,因為它會建立一個不需要的對象,迫使垃圾收集器更頻繁地運行。
public int sumEvenNumbers(List intList) {
int sum = 0;
for (Integer i : intList) {
if (i % 2 == 0) {
sum += i;
}
}
return sum;
}
在這一段程式碼中,sum +=i
它將被擴展為sum = sum + i
. 從「+
」運算子開始,JVM 開始拆箱,因為「+
」運算子不能套用於 Integer 物件。然後結果被自動打包回來。在JDK 1.5之前,資料類型int
和Integer是不同的。在方法重載的情況下,使用這兩種類型沒有問題。隨著自動打包/拆包的出現,這變得更加困難。一個例子是remove()
中的重載方法ArrayList
。該類別ArrayList
有兩個刪除方法 -remove(index)
和remove(object)
。在這種情況下,不會發生方法重載,並且會使用適當的參數來呼叫相應的方法。
結論
自動裝箱是將原始資料型別隱式轉換為對應包裝類別(物件)的機制。編譯器透過方法valueOf()
將原始型別轉換為對象,透過方法IntValue()
等doubleValue()
取得對象的原始型別。自動裝箱將布林類型轉換boolean
為布林型、byte
位元組型char
、字元型 float
、浮點型、int
整數型、long
長整型、short
短整型。拆包以相反的方向進行。 來源文章
GO TO FULL VERSION