ในบทความนี้ เราจะดูคุณลักษณะใน Java ที่เรียกว่าautoboxing
/unboxing การทำกล่องอัตโนมัติและการแกะกล่องเป็นฟังก์ชันในการแปลงประเภทดั้งเดิมเป็นประเภทวัตถุและในทางกลับกัน
![การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 1]()
กระบวนการทั้งหมดดำเนินการโดยอัตโนมัติโดย Java Runtime Environment (JRE) แต่คุณควรระมัดระวังเมื่อใช้ฟังก์ชันนี้ เนื่องจาก... อาจส่งผลต่อประสิทธิภาพของโปรแกรมของคุณ
การแนะนำ
ในเวอร์ชันที่ต่ำกว่า JDK 1.5 ไม่ใช่เรื่องง่ายที่จะแปลงประเภทข้อมูลพื้นฐาน เช่น, ,
int
เป็น
char
คลาสwrapper Integer, Character, Float, Double ตั้งแต่ JDK 5 เป็นต้นไป ฟังก์ชันการทำงานนี้ซึ่งแปลงประเภทดั้งเดิมเป็นอ็อบเจ็กต์ที่เทียบเท่ากัน จะถูกนำไปใช้โดยอัตโนมัติ คุณสมบัตินี้เรียกว่า
Autoboxing กระบวนการย้อนกลับตามลำดับคือ
Unboxingเช่น กระบวนการแปลงวัตถุให้เป็นประเภทดั้งเดิมที่สอดคล้องกัน โค้ดตัวอย่างสำหรับ autoboxing และ unboxing มีดังต่อไปนี้:
Autoboxingfloat
double
Integer integer = 9;
แกะกล่อง
int in = 0;
in = new Integer(9);
การบรรจุและแกะกล่องอัตโนมัติจะใช้เมื่อใด? Autoboxing ถูกใช้โดยคอมไพเลอร์ Java ภายใต้เงื่อนไขต่อไปนี้:
- เมื่อค่าของประเภทดั้งเดิมถูกส่งผ่านไปยังวิธีการเป็นพารามิเตอร์วิธีการ ซึ่งคาดว่าวัตถุของคลาส wrapper ที่สอดคล้องกัน
- เมื่อกำหนดค่าประเภทดั้งเดิมให้กับตัวแปรของคลาส wrapper ที่สอดคล้องกัน
พิจารณาตัวอย่างต่อไปนี้:
รายการ 1:รหัสอย่างง่ายที่แสดงกล่องอัตโนมัติ
public int sumEvenNumbers(List<Integer> intList ) {
int sum = 0;
for (Integer i: intList )
if ( i % 2 == 0 )
sum += i;
return sum;
}
ก่อนหน้า jdk 1.5 โค้ดด้านบนจะทำให้เกิดข้อผิดพลาดในการคอมไพล์เนื่องจากตัวดำเนินการส่วนที่เหลือ % และ unary plus += ไม่สามารถนำไปใช้กับคลาส wrapper ได้ แต่ใน jdk 1.5 และสูงกว่าโค้ดนี้จะคอมไพล์โดยไม่มีข้อผิดพลาด โดยแปลง Integer เป็น
int
. Unboxing ถูกใช้โดยคอมไพเลอร์ Java ภายใต้เงื่อนไขต่อไปนี้:
- เมื่อวัตถุถูกส่งผ่านเป็นพารามิเตอร์ไปยังวิธีการที่คาดว่าจะมีชนิดดั้งเดิมที่สอดคล้องกัน
- เมื่อวัตถุถูกกำหนดให้กับตัวแปรประเภทดั้งเดิมที่สอดคล้องกัน
ลองพิจารณาตัวอย่างต่อไปนี้:
รายการ 2:โค้ดธรรมดาที่แสดงการแกะกล่อง
import java.util.ArrayList;
import java.util.List;
public class UnboxingCheck {
public static void main(String[] args) {
Integer in = new Integer(-8);
int absVal = absoluteValue(in);
System.out.println("absolute value of " + in + " = " + absVal);
List<Double> doubleList = new ArrayList<Double>();
doubleList.add(3.1416);
double phi = doubleList.get(0);
System.out.println("phi = " + phi);
}
public static int absoluteValue(int i) {
return (i < 0) ? -i : i;
}
}
การทำกล่องอัตโนมัติและการแกะกล่องช่วยให้นักพัฒนาสามารถเขียนโค้ดที่อ่านและเข้าใจได้ง่าย ตารางต่อไปนี้แสดงประเภทข้อมูลดั้งเดิมและออบเจ็กต์ wrapper ที่เกี่ยวข้อง
ประเภทดั้งเดิม |
คลาสเชลล์ |
บูลีน |
บูลีน |
ไบต์ |
ไบต์ |
ถ่าน |
อักขระ |
ลอย |
ลอย |
ภายใน |
จำนวนเต็ม |
ยาว |
ยาว |
สั้น |
สั้น |
ตารางที่ 1:ประเภทดั้งเดิมและคลาส wrapper ที่เทียบเท่ากับตัวดำเนินการเปรียบเทียบ สามารถใช้ Autoboxing และ unboxing กับตัวดำเนินการเปรียบเทียบได้ ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าสิ่งนี้เกิดขึ้นได้อย่างไร:
รายการ 3:โค้ดตัวอย่างที่แสดง autoboxing และ unboxing ด้วยตัวดำเนินการเปรียบเทียบ
public class BoxedComparator {
public static void main(String[] args) {
Integer in = new Integer(25);
if (in < 35)
System.out.println("Value of int = " + in);
}
}
การบรรจุอัตโนมัติและการแกะบรรจุภัณฑ์เมื่อมีการโอเวอร์โหลดวิธีการ การบรรจุอัตโนมัติและการแกะบรรจุภัณฑ์จะดำเนินการเมื่อมีการโอเวอร์โหลดวิธีการตามกฎต่อไปนี้:
- การขยายตัว "เอาชนะ" บรรจุภัณฑ์ในสถานการณ์ที่มีตัวเลือกระหว่างการขยายและบรรจุภัณฑ์ การขยายจะดีกว่า
รายการ 4:โค้ดตัวอย่างที่แสดงประโยชน์ของการโอเวอร์โหลด
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
- การขยายตัวเอาชนะจำนวนอาร์กิวเมนต์ที่แปรผันได้ ในสถานการณ์ที่กลายเป็นตัวเลือกระหว่างการขยายและจำนวนอาร์กิวเมนต์ที่แปรผัน การขยายจะดีกว่า
รายการ 5:โค้ดตัวอย่างที่แสดงประโยชน์ของการโอเวอร์โหลด
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);
}
}
- การบรรจุจะเอาชนะจำนวนอาร์กิวเมนต์ที่แปรผันได้ ในสถานการณ์ที่กลายเป็นตัวเลือกระหว่างการบรรจุและจำนวนอาร์กิวเมนต์ที่แปรผันได้ การบรรจุจะดีกว่า
รายการ 6:โค้ดตัวอย่างที่แสดงประโยชน์ของการโอเวอร์โหลด
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);
}
}
คุณควรคำนึงถึงสิ่งต่อไปนี้ในขณะที่ใช้การบรรจุอัตโนมัติ: ดังที่เราทราบ คุณสมบัติที่ดีทุกประการย่อมมีข้อเสียเปรียบ บรรจุภัณฑ์อัตโนมัติก็ไม่มีข้อยกเว้นในเรื่องนี้ หมายเหตุสำคัญบางประการที่นักพัฒนาซอฟต์แวร์ควรคำนึงถึงเมื่อใช้คุณลักษณะนี้:
- การเปรียบเทียบวัตถุกับ
==
ตัวดำเนินการ ' ' อาจทำให้เกิดความสับสน เนื่องจากสามารถนำไปใช้กับประเภทและวัตถุดั้งเดิมได้ เมื่อนำตัวดำเนินการนี้ไปใช้กับออบเจ็กต์ ตัวดำเนินการจะเปรียบเทียบการอ้างอิงกับออบเจ็กต์ ไม่ใช่ตัวออบเจ็กต์เอง
รายการ 7:โค้ดตัวอย่างที่แสดงการเปรียบเทียบ
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 รวมแล้ว ออบเจ็กต์ที่แคชไว้เหล่านี้อาจมีพฤติกรรมแตกต่างออกไป
- ประสิทธิภาพการทำงานลดลง การทำ Autoboxing หรือ Unboxing จะทำให้ประสิทธิภาพของแอปพลิเคชันลดลง เนื่องจากจะสร้างวัตถุที่ไม่ต้องการซึ่งบังคับให้ตัวรวบรวมขยะทำงานบ่อยขึ้น
ข้อเสียของ AutoBoxing แม้ว่า AutoBoxing มีข้อดีหลายประการ แต่ก็มีข้อเสียดังต่อไปนี้
รายการ 8:โค้ดตัวอย่างที่แสดงปัญหาด้านประสิทธิภาพ
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 จะเริ่มแกะกล่องเนื่องจาก
+
ไม่สามารถใช้ตัวดำเนินการ ' ' กับอ็อบเจ็กต์จำนวนเต็มได้ จากนั้นผลลัพธ์ก็จะถูกบรรจุกลับอัตโนมัติ ก่อน JDK 1.5 ชนิดข้อมูล
int
และจำนวนเต็มจะแตกต่างกัน ในกรณีที่วิธีการโอเวอร์โหลด ทั้งสองประเภทนี้ก็ถูกนำมาใช้โดยไม่มีปัญหา เมื่อมีการบรรจุ/แกะกล่องอัตโนมัติ การดำเนินการนี้กลายเป็นเรื่องยากมากขึ้น ตัวอย่างนี้คือวิธีการโอเวอร์โหลด
remove()
ใน
ArrayList
. คลาส
ArrayList
มีสองวิธีการลบ -
remove(index)
และ
remove(object)
. ในกรณีนี้ วิธีการโอเวอร์โหลดจะไม่เกิดขึ้น และวิธีการที่เกี่ยวข้องจะถูกเรียกพร้อมกับพารามิเตอร์ที่เหมาะสม
บทสรุป
การทำกล่องอัตโนมัติเป็นกลไกในการแปลงประเภทข้อมูลดั้งเดิมเป็นคลาส wrapper (อ็อบเจ็กต์) ที่สอดคล้องกันโดยปริยาย คอมไพเลอร์ใช้วิธี การแปลงประเภทดั้งเดิมเป็นอ็อบเจ็กต์ และ
valueOf()
วิธีการ ฯลฯ เพื่อให้ได้ประเภทดั้งเดิมของอ็อบเจ็กต์ Autoboxing แปลงประเภทบูลีนเป็นบูลีน เป็นไบต์ เป็นอักขระลอยเป็นจำนวนเต็ม เป็นยาวเป็นสั้น การแกะบรรจุภัณฑ์เกิดขึ้นในทิศทางตรงกันข้าม
บทความต้นฉบับIntValue()
doubleValue()
boolean
byte
char
float
int
long
short
GO TO FULL VERSION