คือการแปลงอัตโนมัติของ Java ระหว่าง (, ) กับ ของมัน (, ) มันสะดวกแต่มีกับดักที่ละเอียดอ่อน ทั้ง overhead ด้านประสิทธิภาพ, พฤติกรรม ที่น่าประหลาดใจ และความเสี่ยงต่อ
intdoubleIntegerDouble==NullPointerExceptionInteger boxed = 42; // autoboxing: int → Integer (Integer.valueOf(42))
int unboxed = boxed; // auto-unboxing: Integer → int (boxed.intValue())
List<Integer> nums = new ArrayList<>();
nums.add(5); // autoboxes int 5 → Integer (collections need objects)
int x = nums.get(0); // auto-unboxes Integer → int
มันเกิดขึ้นโดยอัตโนมัติเพราะคอลเลกชันและ generic ต้องการอ็อบเจกต์ (คุณไม่สามารถมี List<int> ได้) ดังนั้น Java จึง box primitive ให้อย่างโปร่งใส
Integer a = 1000;
Integer b = 1000;
a == b; // ❌ FALSE — different Integer OBJECTS (reference comparison)
a.equals(b); // ✅ true — value comparison
// the WORSE trap — the Integer cache makes small values seem to work:
Integer c = 100, d = 100;
c == d; // TRUE — Java CACHES Integers from -128 to 127 (same object)
Integer e = 200, f = 200;
e == f; // FALSE — outside the cache range → different objects
สิ่งนี้ร้ายกาจ: == กับ Integer ทำงานได้กับค่าเล็ก ๆ (ที่ถูก cache ไว้) แต่ ล้มเหลวกับค่าใหญ่ โค้ดที่ดูเหมือนถูกต้องในตอนทดสอบกลับพังใน production ให้ใช้ .equals() เสมอสำหรับการเปรียบเทียบค่าของ wrapper หรือ unbox เป็น primitive ก่อน
Integer value = null; // a wrapper can be null
int x = value; // 💥 NullPointerException — unboxing null calls null.intValue()
Map<String, Integer> map = new HashMap<>();
int count = map.get("missing"); // 💥 NPE — get() returns null, then unboxing fails
การ unbox wrapper ที่เป็น null จะ throw NPE เป็น crash ที่พบบ่อยและน่าประหลาดใจ โดยเฉพาะกับการค้นหาใน map ที่คืนค่า null
// ❌ autoboxing in a hot loop — creates millions of Integer objects (GC pressure, slow)
Long sum = 0L; // WRONG type — wrapper
for (long i = 0; i < 1_000_000; i++) {
sum += i; // unbox, add, re-box → new Long each iteration!
}
// ✅ use primitives in hot paths
long sum = 0L; // primitive — no boxing
การ box/unbox ซ้ำ ๆ สร้างอ็อบเจกต์มากเกินไป กระทบประสิทธิภาพในลูปที่รันถี่
Autoboxing สะดวกและพบได้ทั่วไป (คอลเลกชันและ generic ทั้งหมดอาศัยมัน) แต่กับดักของมันก่อให้เกิดบั๊กจริงที่วินิจฉัยได้ยาก
กับดัก == อันตรายเป็นพิเศษ: การเปรียบเทียบ Integer ด้วย == ทำงานได้กับค่าเล็กที่ถูก cache (-128 ถึง 127) แต่ล้มเหลวเงียบ ๆ กับค่าที่ใหญ่กว่า เป็นบั๊กที่ผ่านการทดสอบแต่พังใน production ทำให้ .equals() (หรือการ unbox) เป็นสิ่งจำเป็นสำหรับการเปรียบเทียบ wrapper NullPointerException จากการ unbox wrapper ที่เป็น null (พบบ่อยกับการค้นหาใน map) เป็นอีก crash ที่เกิดบ่อย
และการ box ในลูปที่รันถี่ (hot loop) สร้างอ็อบเจกต์โดยไม่จำเป็น กระทบประสิทธิภาพ
การเข้าใจว่า box เกิดขึ้นเมื่อไร, ปัญหาการเปรียบเทียบค่าเทียบกับ reference, ความเสี่ยงจากการ unbox null และการใช้ primitive ในโค้ดที่เน้นประสิทธิภาพ เป็นสิ่งสำคัญต่อการเขียน Java ที่ถูกต้องและมีประสิทธิภาพ และพฤติกรรม == จาก Integer cache เป็นคำถามสัมภาษณ์คลาสสิกที่เผยให้เห็นความเข้าใจเชิงลึก