JavaRush /จาวาบล็อก /Random-TH /การทำกล่องอัตโนมัติและการแกะกล่องใน Java
Viacheslav
ระดับ

การทำกล่องอัตโนมัติและการแกะกล่องใน Java

เผยแพร่ในกลุ่ม
<h2>บทนำ</h2>ภาษาการเขียนโปรแกรม เช่น ภาษาที่ผู้คนพูด ชีวิตและการเปลี่ยนแปลง มีปรากฏการณ์ใหม่ๆ ปรากฏขึ้นเพื่อทำให้ภาษาใช้งานได้สะดวกยิ่งขึ้น และดังที่เราทราบ ภาษาควรแสดงความคิดของเราได้อย่างสะดวก
การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 1
ดังนั้นใน Java SE 5 จึงมีการนำกลไก boxing/unboxing มาใช้ และบทช่วยสอนแยกต่างหากจาก Oracle นั้นเน้นไปที่คุณสมบัติของวิธีการแสดงความคิดนี้: Autoboxing และ Unboxing . <h2>ออโต้แพ็คมวย</h2>มาดูตัวอย่างออโต้แพ็คมวยกัน ก่อนอื่นเรามาดูกันว่ามันทำงานอย่างไร ลองใช้เว็บไซต์compilejava.netและสร้างคลาส:
public class App {
    public static void main(String[] args) {
        Integer portNumber = 8080;
        if (args.length != 0) {
            portNumber = Integer.valueOf(args[0]);
        }
        System.out.println("Port number is: " + portNumber);
    }
}
รหัสง่ายๆ เราสามารถระบุพารามิเตอร์อินพุตและเปลี่ยนค่าพอร์ตได้ อย่างที่เราเห็นเพราะว่า เรา อ่านค่าพอร์ตจากStringพารามิเตอร์ เราได้Integerมันมาจากการส่งผ่าน Integer.valueOfดังนั้นเราจึงถูกบังคับให้ระบุว่าไม่ใช่ประเภทดั้งเดิม แต่เป็นประเภทIntegerอ็อบเจ็กต์ ในทางกลับกัน เรามีตัวแปรอ็อบเจ็กต์ และค่าเริ่มต้นคือค่าดั้งเดิม และมันก็ได้ผล แต่เราไม่เชื่อเรื่องเวทมนตร์ใช่ไหม? มาดู "ใต้ฝากระโปรง" ตามที่พวกเขาพูดกันดีกว่า ดาวน์โหลดซอร์สโค้ดจาก Complejava.net โดยคลิก "ดาวน์โหลด ZIP" หลังจากนั้นให้แตกไฟล์เก็บถาวรที่ดาวน์โหลดมาลงในไดเร็กทอรีแล้วไปที่ไฟล์นั้น เอาล่ะ มาทำกันjavap -c -p App.classโดยที่ App.class เป็นไฟล์คลาสที่คอมไพล์แล้วสำหรับชั้นเรียนของคุณ เราจะเห็นเนื้อหาดังนี้:
การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 2
นี่คือ "bytecode" ที่มีชื่อเสียงเหมือนกัน แต่สิ่งสำคัญสำหรับเราตอนนี้คือสิ่งที่เราเห็น ขั้นแรก 8080 ดั้งเดิมจะถูกวางบนสแต็กการดำเนินการเมธอด จากนั้นจึง ดำเนิน การInteger.valueOf นี่คือ “ความมหัศจรรย์” ของการชกมวย และภายในเวทย์มนตร์มีลักษณะดังนี้:
การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 3
โดยพื้นฐานแล้วจะมีการนำอันใหม่Integerหรือจะได้มาIntegerจากแคช (แคชนั้นไม่มีอะไรมากไปกว่าอาร์เรย์ของจำนวนเต็ม) ขึ้นอยู่กับค่าของตัวเลข แน่นอนว่าIntegerไม่ใช่แค่คนเดียวเท่านั้นที่โชคดีมาก มีรายการประเภทดั้งเดิมที่เกี่ยวข้องทั้งหมดและ wrappers (คลาสที่แสดงถึงดั้งเดิมในโลก OOP) รายการนี้ระบุไว้ที่ด้านล่างของบทช่วยสอนจาก Oracle: “ Autoboxing and Unboxing ” เป็นที่น่าสังเกตทันทีว่าอาร์เรย์ที่สร้างจากพื้นฐานไม่มี "wrapper" โดยไม่ต้องเชื่อมต่อกับไลบรารีของบุคคลที่สาม เหล่านั้น. Arrays.asListจะไม่ทำมาจากint[]สำหรับเราListจากInteger's <h2>การแกะกล่อง</h2>กระบวนการย้อนกลับของการแกะกล่องเรียกว่าการแกะกล่อง การแกะกล่อง ลองดูตัวอย่างการแกะออก:
public class App {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please, enter params");
            return;
        }
      	int value = Math.abs(Integer.valueOf(args[0]));
        System.out.println("Absolute value is: " + value);
    }

}
Math.absยอมรับเฉพาะดั้งเดิมเท่านั้น จะทำอย่างไร? คลาส wrapper มีวิธีการพิเศษสำหรับกรณีนี้ที่ส่งกลับค่าดั้งเดิม ตัวอย่างเช่น นี่ คือIntegerเมธอดintValue ถ้าเราดูที่ bytecode มันจะเป็นดังนี้:
การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 4
เห็นได้ชัดว่าไม่มีเวทย์มนตร์ ทุกอย่างอยู่ใน Java มันทำงานได้ "ด้วยตัวเอง" เพื่อความสะดวกของเรา <h2>คราด</h2>
การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 5
เครื่องมือใด ๆ หากใช้ไม่ถูกต้องจะกลายเป็นอาวุธที่น่าเกรงขามต่อตัวมันเอง และกลไกการชกมวย / แกะกล่องอัตโนมัติใน Java ก็ไม่มีข้อยกเว้น การเปรียบเทียบแรกที่ชัดเจนคือ==ผ่าน ฉันคิดว่าสิ่งนี้ชัดเจน แต่ลองดูอีกครั้ง:
public static void main(String[] args) {
    Integer inCacheValue = 127;
    Integer inCacheValue2 = 127;
    Integer notInCache = 128; // new Integer(129)
    Integer notInCache2 = 128; // new Integer(129)
    System.out.println(inCacheValue == inCacheValue2); //true
    System.out.println(notInCache == notInCache2); //false
}
ในกรณีแรก ค่าจะถูกนำมาจากIntegerแคชค่า (ดูคำอธิบายของ Boxing ด้านบน) และในกรณีที่สอง ออบเจ็กต์ใหม่จะถูกสร้างขึ้นในแต่ละครั้ง แต่ที่นี่ก็คุ้มค่าที่จะจอง ลักษณะการทำงานนี้ขึ้นอยู่กับขอบเขตสูงของแคช ( java.lang.Integer.IntegerCache.high ) นอกจากนี้ ขีดจำกัดนี้อาจเปลี่ยนแปลงเนื่องจากการตั้งค่าอื่นๆ คุณสามารถอ่านการสนทนาในหัวข้อนี้ได้ที่ stackoverflow: แคช Integer มีขนาดใหญ่แค่ไหน โดยปกติแล้ว วัตถุจะต้องถูกเปรียบเทียบโดยใช้ความเท่าเทียมกัน System.out.println(notInCache.equals(notInCache2)); ปัญหาที่สองที่เกี่ยวข้องกับกลไกเดียวกันคือประสิทธิภาพ การชกมวยใน Java เทียบเท่ากับการสร้างวัตถุใหม่ หากตัวเลขไม่รวมอยู่ในค่าแคช (เช่น -128 ถึง 127) วัตถุใหม่จะถูกสร้างขึ้นในแต่ละครั้ง หากมีการดำเนินการบรรจุภัณฑ์แบบกะทันหัน (เช่นการชกมวย) จะทำให้วัตถุที่ไม่จำเป็นและการใช้ทรัพยากรเพิ่มขึ้นอย่างมากสำหรับการทำงานของคนเก็บขยะ ดังนั้นอย่าประมาทกับเรื่องนี้จนเกินไป คราดอันที่สามที่เจ็บปวดไม่น้อยนั้นเกิดจากกลไกเดียวกัน:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
ในโค้ดนี้ บุคคลนั้นพยายามที่จะไม่ผ่านข้อผิดพลาดอย่างชัดเจน แต่ไม่มีการตรวจสอบnull. หากเป็นเรื่องของอินพุตnullแทนที่จะเป็นข้อผิดพลาดที่เข้าใจได้ เราจะได้รับข้อผิดพลาดที่เข้าใจยากNullPointerException. เพราะถ้าเทียบกัน Java จะพยายามรันvalue.intValueแล้วพังเพราะ... valueจะnull. <h2>บทสรุป</h2>กลไก boxing/unboxing ช่วยให้โปรแกรมเมอร์เขียนโค้ดน้อยลง และบางครั้งก็ไม่ได้คิดถึงการแปลงจากพื้นฐานไปเป็นอ็อบเจ็กต์และย้อนกลับด้วยซ้ำ แต่นั่นไม่ได้หมายความว่าคุณควรลืมวิธีการทำงาน มิฉะนั้นคุณอาจทำผิดพลาดที่อาจไม่ปรากฏขึ้นทันที เราไม่ควรพึ่งพาบางส่วนของระบบที่ไม่ได้อยู่ภายใต้การควบคุมของเราอย่างสมบูรณ์ (เช่น ขอบเขตจำนวนเต็ม) แต่อย่าลืมข้อดีทั้งหมดของคลาส wrapper (เช่นInteger) บ่อยครั้งที่คลาส wrapper เหล่านี้มีชุดวิธีการคงที่เพิ่มเติม ซึ่งจะทำให้ชีวิตของคุณดีขึ้น และโค้ดของคุณแสดงออกได้มากขึ้น นี่คือตัวอย่างการติดตามผล:
public static void main(String[] args) {
    int first = 1;
    int second = 5;
    System.out.println(Integer.max(first, second));
    System.out.println(Character.toLowerCase('S'));
}
ข้อสรุปที่ถูกต้องจากทุกสิ่งคือไม่มีเวทย์มนตร์มีการตระหนักรู้บางอย่าง และไม่ใช่ทุกอย่างจะเป็นอย่างที่เราคาดหวังเสมอไป ตัวอย่างเช่น ไม่มีบรรจุภัณฑ์: System.out.println("The number is " + 8); ตัวอย่างข้างต้นจะได้รับการปรับให้เหมาะสมโดยคอมไพเลอร์เป็นหนึ่งบรรทัด นั่นคือเหมือนกับว่าคุณเขียนว่า "ตัวเลขคือ 8" และในตัวอย่างด้านล่าง จะไม่มีบรรจุภัณฑ์เช่นกัน:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
เป็นไปได้อย่างไรเมื่อเราprintlnรับวัตถุเป็นอินพุตและจำเป็นต้องเชื่อมต่อสายด้วยวิธีใดวิธีหนึ่ง เส้น... ใช่ นั่นคือเหตุผลว่าทำไมจึงไม่มีบรรจุภัณฑ์เช่นนี้ มีIntegerวิธีการแบบคงที่ แต่บางวิธีก็เป็นpackage. นั่นคือเราไม่สามารถใช้งานได้ แต่ใน Java เองสามารถใช้งานได้ นี่เป็นกรณีที่นี่ เมธอด getChars จะถูกเรียก ซึ่งสร้างอาร์เรย์ของอักขระจากตัวเลข อีกครั้งไม่มีเวทย์มนตร์แค่ Java) ดังนั้นในสถานการณ์ที่ไม่ชัดเจน คุณเพียงแค่ต้องดูการนำไปปฏิบัติและอย่างน้อยก็มีบางอย่างเข้าที่ #เวียเชสลาฟ
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION