JavaRush /จาวาบล็อก /Random-TH /การห่อ การแกะ และการบรรจุ

การห่อ การแกะ และการบรรจุ

เผยแพร่ในกลุ่ม
สวัสดี! คุณค่อนข้างคุ้นเคยกับประเภทดั้งเดิมอยู่แล้ว และเคยทำงานกับมันมาบ้างแล้ว การห่อ การแกะ และการบรรจุ - 1พื้นฐานในการเขียนโปรแกรมและโดยเฉพาะ Java มีข้อดีหลายประการ: ใช้หน่วยความจำน้อย จึงเพิ่มประสิทธิภาพของโปรแกรม และแบ่งออกเป็นช่วงของค่าอย่างชัดเจน อย่างไรก็ตาม ในกระบวนการเรียนรู้ Java เราได้ทำซ้ำมากกว่าหนึ่งครั้ง เหมือนมนต์ “ ใน Java ทุกอย่างเป็นวัตถุ ” แต่คำดั้งเดิมเป็นการหักล้างคำเหล่านี้โดยตรง พวกเขาไม่ใช่วัตถุ ดังนั้นหลักการ “ทุกสิ่งเป็นวัตถุ” จึงผิดใช่ไหม? ไม่เชิง. ใน Java primitive type ทุกประเภทมีพี่น้องฝาแฝด ซึ่งเป็นคลาส wrapper ( Wrapper) กระดาษห่อคืออะไร? wrapper เป็นคลาสพิเศษที่เก็บค่าของดั้งเดิมไว้ภายในตัวมันเอง แต่เนื่องจากนี่คือคลาส จึงสามารถสร้างอินสแตนซ์ของตัวเองได้ พวกเขาจะเก็บค่าดั้งเดิมที่จำเป็นไว้ข้างในในขณะที่เป็นวัตถุจริง ชื่อของคลาส wrapper นั้นคล้ายคลึงกับชื่อของคลาสพื้นฐานที่เกี่ยวข้องมาก หรือเหมือนกันโดยสิ้นเชิง ดังนั้นจึงง่ายต่อการจดจำ
คลาส Wrapper สำหรับประเภทข้อมูลดั้งเดิม
ประเภทข้อมูลดั้งเดิม คลาส Wrapper
ภายใน จำนวนเต็ม
สั้น สั้น
ยาว ยาว
ไบต์ ไบต์
ลอย ลอย
สองเท่า สองเท่า
ถ่าน อักขระ
บูลีน บูลีน
อ็อบเจ็กต์คลาส Wrapper ถูกสร้างขึ้นเหมือนกับที่อื่น:
public static void main(String[] args) {

   Integer i = new Integer(682);

   Double d = new Double(2.33);

   Boolean b = new Boolean(false);
}
คลาส Wrapper ช่วยให้คุณสามารถลดข้อเสียของประเภทดั้งเดิมได้ สิ่งที่ชัดเจนที่สุดคือแบบดั้งเดิมไม่มีวิธีการ ตัวอย่างเช่น ไม่มีเมธอดtoString()ดังนั้น คุณจึงไม่สามารถแปลงตัวเลขintเป็นสตริงได้ แต่ด้วยคลาส wrapper Integerมันเป็นเรื่องง่าย
public static void main(String[] args) {

   Integer i = new Integer(432);

   String s = i.toString();
}
จะมีปัญหากับการแปลงแบบย้อนกลับด้วย สมมติว่าเรามีสตริงที่เรารู้ว่ามีตัวเลขอยู่ด้วย อย่างไรก็ตาม ในกรณีของประเภทดั้งเดิมintเราจะไม่สามารถรับหมายเลขนี้จากสตริงและเปลี่ยนให้เป็นตัวเลขได้ แต่ต้องขอบคุณคลาส wrapper ที่ทำให้เรามีโอกาสนี้แล้ว
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ได้ นอกจากนี้ นอกเหนือจากวิธีการแล้ว คลาส wrapper ยังมีฟิลด์คงที่ซึ่งสะดวกต่อการใช้งานมาก ตัวอย่างเช่น ลองนึกภาพว่าคุณกำลังเผชิญกับงาน: พิมพ์จำนวนสูงสุดที่เป็นไปได้ไปยังคอนโซล intจากนั้นพิมพ์จำนวนขั้นต่ำที่เป็นไปได้ งานนี้ดูเหมือนจะเป็นงานเบื้องต้น แต่คุณคงไม่สามารถทำได้หากไม่มี Google และคลาส wrapper ช่วยให้คุณสามารถแก้ไข “ปัญหาในชีวิตประจำวัน” ต่อไปนี้ได้อย่างง่ายดาย:
public class Main {
   public static void main(String[] args) {

       System.out.println(Integer.MAX_VALUE);
       System.out.println(Integer.MIN_VALUE);
   }
}
สาขาดังกล่าวช่วยให้คุณไม่เสียสมาธิจากงานที่จริงจังกว่านี้ ไม่ต้องพูดถึงความจริงที่ว่าในกระบวนการพิมพ์หมายเลข2147483647 (นี่คือ MAX_VALUE พอดี) จึงไม่น่าแปลกใจที่จะพิมพ์ผิด :) นอกจากนี้ในการบรรยายครั้งหนึ่งก่อนหน้านี้เราได้ดึงความสนใจไปที่ความจริงที่ว่าวัตถุของคลาส wrapper ไม่เปลี่ยนรูป (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แทนที่จะเปลี่ยนสถานะของออบเจ็กต์ wrapper ออบเจ็กต์ใหม่ทั้งหมดจะถูกสร้างขึ้นในหน่วยความจำ เหตุใดผู้สร้าง Java จึงตัดสินใจเก็บประเภทดั้งเดิมไว้ในภาษาในที่สุด เนื่องจากทุกสิ่งควรเป็นวัตถุ และเรามีคลาส wrapper อยู่แล้วที่สามารถใช้เพื่อแสดงทุกสิ่งที่ primitive แสดงออก ทำไมไม่ปล่อยมันไว้ในภาษาและลบ primitive ออกไปล่ะ? คำตอบนั้นง่าย - ประสิทธิภาพ ประเภทดั้งเดิมเรียกว่าดั้งเดิมเนื่องจากไม่มีคุณลักษณะ "หนัก" มากมายของวัตถุ ใช่ วัตถุมีวิธีการที่สะดวกมากมาย แต่คุณไม่จำเป็นต้องใช้มันเสมอไป บางครั้งคุณแค่ต้องการตัวเลข 33 หรือ 2.62 หรือค่าของtrue/ falseในสถานการณ์ที่ประโยชน์ของอ็อบเจ็กต์ไม่เกี่ยวข้องและไม่จำเป็นสำหรับการทำงานของโปรแกรม primitive จะทำงานได้ดีขึ้นมาก

บรรจุอัตโนมัติ/เปิดออกอัตโนมัติ

หนึ่งในคุณสมบัติของ primitive และคลาส wrapper ใน Java คือ autoboxing/autounboxing การห่อ การแกะ และการบรรจุ - 2 มาทำความเข้าใจแนวคิดนี้กันดีกว่า ดังที่คุณและฉันได้เรียนรู้มาก่อนหน้านี้แล้ว Java เป็นภาษาเชิงวัตถุ ซึ่งหมายความว่าโปรแกรมทั้งหมดที่เขียนด้วย Java ประกอบด้วยวัตถุ ดั้งเดิมไม่ใช่วัตถุ อย่างไรก็ตาม ตัวแปรคลาส wrapper สามารถกำหนดค่าเป็นประเภทดั้งเดิมได้ กระบวนการนี้เรียกว่าออโต้บ็อกซ์ ในทำนองเดียวกัน ตัวแปรประเภทดั้งเดิมสามารถกำหนดให้กับอ็อบเจ็กต์ของคลาส wrapper ได้ กระบวนการนี้เรียกว่า autounboxing ตัวอย่างเช่น:
public class Main {
   public static void main(String[] args) {
       int x = 7;
       Integer y = 111;
       x = y; // auto unpacking
       y = x * 123; // autopacking
   }
}
ในบรรทัดที่ 5 เรากำหนดค่าดั้งเดิม x ของ y ซึ่งเป็นอ็อบเจ็กต์ของคลาสIntegerwrapper อย่างที่คุณเห็นไม่จำเป็นต้องดำเนินการใด ๆ เพิ่มเติมสำหรับสิ่งนี้: คอมไพเลอร์รู้สิ่งนั้นintและIntegerอันที่จริงเป็นสิ่งเดียวกัน นี่คือการเปิดออกอัตโนมัติ สิ่งเดียวกันนี้เกิดขึ้นกับ autoboxing ในบรรทัดที่ 6: object y สามารถกำหนดค่าของ primitives ได้อย่างง่ายดาย (x*123) นี่คือตัวอย่างของการบรรจุอัตโนมัติ นี่คือสาเหตุที่เพิ่มคำว่า "อัตโนมัติ": เพื่อกำหนดการอ้างอิงดั้งเดิมให้กับอ็อบเจ็กต์ของคลาส wrapper (และในทางกลับกัน) คุณไม่จำเป็นต้องทำอะไรเลย ทุกอย่างจะเกิดขึ้นโดยอัตโนมัติ สะดวกใช่ไหม? :) ความสะดวกสบายที่ยอดเยี่ยมอีกประการหนึ่งของการบรรจุอัตโนมัติ/การเปิดบรรจุภัณฑ์อัตโนมัตินั้นแสดงออกมาในการทำงานของวิธีการต่างๆ ความจริงก็คือพารามิเตอร์ของวิธีการยังขึ้นอยู่กับการบรรจุอัตโนมัติและการเปิดบรรจุภัณฑ์อัตโนมัติด้วย และตัวอย่างเช่น ถ้าหนึ่งในนั้นรับวัตถุสองชิ้นเป็นอินพุต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);
   }
}
จุดสำคัญที่ต้องจำ: การทำ autoboxing และ unboxing ใช้ไม่ได้กับ arrays !
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));
   }
}
การพยายามส่งผ่านอาร์เรย์ของดั้งเดิมไปยังวิธีการที่รับอาร์เรย์ของอ็อบเจ็กต์เป็นอินพุตจะทำให้เกิดข้อผิดพลาดในการคอมไพล์ สุดท้ายนี้ เราจะมาเปรียบเทียบ primitive และ wrappers primitives กันอีกครั้งโดยย่อ:
  • มีความได้เปรียบด้านประสิทธิภาพ
กระดาษห่อ:
  • พวกเขาอนุญาตให้คุณไม่ละเมิดหลักการ "ทุกสิ่งเป็นวัตถุ" เพื่อให้ตัวเลขสัญลักษณ์และค่าบูลีนจริง/เท็จไม่หลุดออกจากแนวคิดนี้
  • ขยายความสามารถในการทำงานกับค่าเหล่านี้โดยจัดเตรียมวิธีการและสาขาที่สะดวก
  • จำเป็นเมื่อวิธีการบางอย่างสามารถทำงานได้กับวัตถุโดยเฉพาะ
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION