Java Static Binding และ Dynamic Binding
เมื่อเร็ว ๆ นี้ฉันได้เรียนรู้ความรู้ Java และเรียนรู้การผูกมัดแบบคงที่และมีชีวิตชีวาของ Java จากนั้นฉันสรุปและจัดเรียงความรู้ที่เกี่ยวข้องกับ Baidu เพื่อช่วยเชี่ยวชาญส่วนหนึ่งของความรู้นี้
แนวคิดของการผูกโปรแกรม:
การเชื่อมหมายถึงการเชื่อมโยงของวิธีการเรียกใช้กับคลาส (ตัวถังวิธี) ซึ่งวิธีการตั้งอยู่ สำหรับ Java การผูกมัดจะถูกแบ่งออกเป็นการผูกมัดแบบคงที่และการผูกมัดแบบไดนามิก หรือเรียกว่าการผูกมัดก่อนและผูกพันล่าช้า
การผูกพันคงที่:
วิธีการถูกผูกไว้ก่อนที่โปรแกรมจะถูกดำเนินการ (นั่นคือคุณรู้อยู่แล้วว่าคลาสใดที่วิธีการในกระบวนการรวบรวม) และใช้งานโดยคอมไพเลอร์หรือโปรแกรมเชื่อมต่ออื่น ๆ ตัวอย่างเช่น: C.
มันสามารถเข้าใจได้ง่าย ๆ ว่ามีผลผูกพันในระหว่างระยะเวลาการรวบรวมโปรแกรมสำหรับ Java; ที่นี่มีความชัดเจนโดยเฉพาะอย่างยิ่งว่าวิธีการเดียวใน Java นั้นเป็นที่สิ้นสุดแบบคงที่ส่วนตัวและตัวสร้างที่มีผลผูกพันล่วงหน้า
การผูกมัดแบบไดนามิก:
การเชื่อมโยงในภายหลัง: ผูกตามประเภทของวัตถุเฉพาะที่รันไทม์
หากภาษาใช้การเชื่อมโยงล่าช้ามันจะต้องมีกลไกบางอย่างเพื่อกำหนดประเภทของวัตถุในระหว่างการดำเนินการและการเรียกวิธีการที่เหมาะสมแยกกัน กล่าวอีกนัยหนึ่งคอมไพเลอร์ยังไม่ทราบประเภทวัตถุในเวลานี้ แต่กลไกการเรียกใช้วิธีการสามารถตรวจสอบได้ด้วยตัวเองและค้นหาวิธีการที่ถูกต้อง ภาษาที่แตกต่างกันมีวิธีที่แตกต่างกันในการใช้การผูกมัดล่าช้า แต่อย่างน้อยเราก็สามารถคิดแบบนี้ได้: พวกเขาทั้งหมดจำเป็นต้องติดตั้งข้อมูลพิเศษบางประเภทในวัตถุ
กระบวนการเชื่อมโยงแบบไดนามิก:
ขั้นสุดท้ายแบบคงที่ส่วนตัวและผู้สร้างคือความเข้าใจในการผูกมัด แต่เนิ่นๆ
สำหรับวิธีการส่วนตัวก่อนอื่นไม่สามารถสืบทอดได้ เนื่องจากไม่สามารถสืบทอดได้จึงไม่มีวิธีที่จะเรียกมันผ่านวัตถุของคลาสย่อย แต่สามารถเรียกผ่านวัตถุของคลาสนี้เท่านั้น ดังนั้นจึงอาจกล่าวได้ว่าวิธีการส่วนตัวนั้นถูกผูกไว้กับคลาสที่กำหนดวิธีนี้
แม้ว่าวิธีสุดท้ายจะสามารถสืบทอดได้ แต่ก็ไม่สามารถเขียนทับได้ (แทนที่) แม้ว่าวัตถุระดับเด็กสามารถเรียกได้ แต่วิธีสุดท้ายที่กำหนดไว้ในคลาสพาเรนต์เรียกว่า (จากนี้เราสามารถรู้ได้ว่าวิธีนี้ถูกประกาศว่าเป็นประเภทสุดท้าย แต่ก็คือการป้องกันไม่ให้วิธีการถูกเขียนทับและอีกวิธีหนึ่งคือการปิดการเชื่อมโยงแบบไดนามิกอย่างมีประสิทธิภาพใน Java)
ตัวสร้างไม่สามารถสืบทอดได้ (นอกจากนี้ยังมีการบอกว่า subclasses มรดกแบบไม่มีเงื่อนไขโดยไม่มีเงื่อนไขตัวสร้างพารามิเตอร์ที่ไม่มีพารามิเตอร์ของคลาสแม่เป็นตัวสร้างของพวกเขา แต่โดยส่วนตัวแล้วฉันคิดว่าคำแถลงนี้ไม่เหมาะสมเพราะเรารู้ว่าคลาสย่อยเรียกว่าพารามิเตอร์ของชั้นเรียน ตัวสร้างคลาสหลัก) ดังนั้นคุณยังสามารถรู้ได้ว่าตัวสร้างนี้เป็นคลาสใดที่เป็นของเมื่อรวบรวม
ฉันไม่สามารถอธิบายหลักการเฉพาะของวิธีการคงที่ได้ดี อย่างไรก็ตามจากข้อมูลออนไลน์และการทดลองของฉันเองเราสามารถสรุปได้ว่าวิธีการคงที่สามารถสืบทอดได้โดย subclasses แต่ไม่สามารถเขียนใหม่ (ถูกแทนที่) โดย subclasses แต่สามารถซ่อนได้โดย subclasses (ซึ่งหมายความว่าหากมีวิธีการคงที่ในคลาสพาเรนต์และหากไม่มีวิธีการที่สอดคล้องกันในคลาสย่อยของมันวิธีการในคลาสพาเรนต์จะถูกใช้เมื่อวัตถุคลาสเด็กเรียกวิธีนี้และหากวิธีการเดียวกันถูกกำหนดไว้ในคลาสเด็ก ชั้นผู้ปกครองโดยไม่คำนึงว่าชั้นเด็กมีวิธีการคงที่นี้หรือไม่
จากข้างต้นเราสามารถสรุปได้ว่าหากวิธีการไม่สามารถสืบทอดได้หรือไม่สามารถเขียนทับหลังจากการสืบทอดได้วิธีนี้จะใช้การผูกมัดแบบคงที่
การรวบรวมและการทำงานของ Java
กระบวนการรวบรวม Java เป็นกระบวนการรวบรวมไฟล์ต้นฉบับ Java ลงใน bytecode (รหัสปฏิบัติการ JVM เช่นไฟล์. class) ในกระบวนการนี้ Java ไม่ได้จัดการกับหน่วยความจำ ในกระบวนการนี้คอมไพเลอร์จะทำการวิเคราะห์ไวยากรณ์ หากไวยากรณ์ไม่ถูกต้องจะมีการรายงานข้อผิดพลาด
Java Running Process หมายถึง JVM (Java Virtual Machine) โหลดไฟล์ bytecode และการตีความการดำเนินการ ในกระบวนการนี้เป็นการสร้างเค้าโครงหน่วยความจำและการดำเนินการของโปรแกรม Java อย่างแท้จริง
มีสองวิธีในการดำเนินการ Java bytecode: (1) วิธีการรวบรวมทันที: ล่ามแรกรวบรวมไบต์ลงในรหัสเครื่องแล้วเรียกใช้รหัสเครื่อง; (2) คำอธิบายวิธีการดำเนินการ: ล่ามเสร็จสิ้นการดำเนินการทั้งหมดของโปรแกรม Java bytecode โดยการตีความและดำเนินการโค้ดชิ้นเล็ก ๆ ในแต่ละครั้ง (ที่นี่เราจะเห็นได้ว่าโปรแกรม Java ผ่านการแปลงสองครั้งในระหว่างกระบวนการดำเนินการก่อนอื่นแปลงเป็น bytecode จากนั้นแปลงเป็นรหัสเครื่องนี่เป็นเหตุผลว่าทำไม Java สามารถรวบรวมและเรียกใช้ทุกที่ในการติดตั้งเครื่องเสมือน Java ที่แตกต่างกัน
ดังที่ได้กล่าวไว้ก่อนหน้านี้สำหรับวิธีการใน Java ยกเว้นสำหรับขั้นสุดท้ายคงที่ส่วนตัวและตัวสร้างที่มีการผูกก่อนวิธีอื่น ๆ ทั้งหมดคือการผูกแบบไดนามิก
การเชื่อมโยงแบบไดนามิกทั่วไปเกิดขึ้นภายใต้การประกาศการแปลงของคลาสแม่และชั้นเด็ก:
ตัวอย่างเช่น: ผู้ปกครอง p = เด็กใหม่ ();
รายละเอียดกระบวนการเฉพาะมีดังนี้:
1: คอมไพเลอร์ตรวจสอบประเภทการประกาศและชื่อวิธีของวัตถุ
สมมติว่าเราเรียกเมธอด XF (ARGS) และ X ได้รับการประกาศว่าเป็นวัตถุของคลาส C จากนั้นคอมไพเลอร์จะแสดงรายการวิธีการทั้งหมดที่ชื่อ F ในคลาส C และ F วิธีการที่สืบทอดมาจาก superclass ของคลาส C
2: ถัดไปคอมไพเลอร์จะตรวจสอบประเภทพารามิเตอร์ที่มีให้ในการโทรวิธี
หากพารามิเตอร์ชนิดหนึ่งระหว่างวิธีทั้งหมดที่มีชื่อ F ตรงกับประเภทพารามิเตอร์ที่ได้รับจากการโทรมากที่สุดแล้ววิธีนี้จะเรียกว่า กระบวนการนี้เรียกว่า "ความละเอียดมากเกินไป"
3: เมื่อโปรแกรมรันและใช้การเชื่อมโยงแบบไดนามิกกับวิธีการโทรเครื่องเสมือนต้องเรียกเวอร์ชันวิธีการที่ตรงกับประเภทจริงของวัตถุที่ชี้ไปที่ x
สมมติว่าประเภทจริงคือ d (s subclass ของ c) ถ้าคลาส D กำหนด F (สตริง) จากนั้นวิธีจะเรียกว่ามิฉะนั้นวิธี F (สตริง) จะถูกค้นหาใน superclass ของ d และอื่น ๆ
เมื่อเครื่องเสมือน Java เรียกวิธีการคลาส (วิธีการคงที่) จะเลือกวิธีที่เรียกว่าตามประเภทของการอ้างอิงวัตถุ (มักจะรู้จักในเวลาคอมไพล์) ในทางตรงกันข้ามเมื่อเครื่องเสมือนเรียกใช้วิธีการอินสแตนซ์มันจะเลือกวิธีที่เรียกว่าตามประเภทจริงของวัตถุ (รู้จักกันในรันไทม์เท่านั้น) นี่คือการเชื่อมโยงแบบไดนามิกซึ่งเป็นประเภทของความหลากหลาย การเชื่อมโยงแบบไดนามิกให้ความยืดหยุ่นอย่างมากในการแก้ปัญหาทางธุรกิจจริงและเป็นกลไกที่สวยงามมาก
ซึ่งแตกต่างจากวิธีการเมื่อจัดการกับตัวแปรสมาชิก (ตัวแปรอินสแตนซ์และตัวแปรคลาส) ในคลาส Java มันไม่ได้มีการเชื่อมโยงเวลา แต่มีการผูกมัดแบบคงที่ในความหมายทั่วไป ดังนั้นในกรณีของการแปลงขึ้นไปวิธีการของวัตถุสามารถค้นหาคลาสย่อยในขณะที่แอตทริบิวต์ของวัตถุ (ตัวแปรสมาชิก) ยังคงเป็นแอตทริบิวต์ของคลาสแม่ (การซ่อนตัวของคลาสย่อยจากตัวแปรสมาชิกระดับแม่)
พ่อชั้นเรียนสาธารณะ {ชื่อสตริงที่ได้รับการป้องกัน = "คุณลักษณะของพ่อ"; } ลูกชายระดับสาธารณะขยายพ่อ {ชื่อสตริงที่ได้รับการป้องกัน = "แอตทริบิวต์ลูกชาย"; โมฆะคงที่สาธารณะหลัก (สตริง [] args) {พ่อตัวอย่าง = ลูกชายคนใหม่ (); System.out.println ("เรียกว่าคุณสมบัติ:" + sample.name); - สรุป: ผู้โทรคือคุณลักษณะของพ่อ
ผลลัพธ์นี้แสดงให้เห็นว่าวัตถุของคลาสเด็ก (ที่จับอ้างอิงของคลาสแม่) ถูกเรียกไปยังตัวแปรสมาชิกคลาสแม่ ดังนั้นจึงต้องมีความชัดเจนว่าหมวดหมู่ที่กำหนดเป้าหมายโดยการเชื่อมโยง (ไดนามิก) เป็นเพียงวิธีการของวัตถุ
ตอนนี้พยายามโทรหาชื่อตัวแปรสมาชิก subclass แล้วจะทำอย่างไร? วิธีที่ง่ายที่สุดคือการห่อหุ้มตัวแปรสมาชิกลงในแบบฟอร์มวิธี getter
รหัสมีดังนี้:
พ่อชั้นเรียนสาธารณะ {ชื่อสตริงที่ได้รับการป้องกัน = "คุณลักษณะของพ่อ"; สตริงสาธารณะ getName () {ชื่อคืน; }} ลูกชายระดับสาธารณะขยายพ่อ {ชื่อสตริงที่ได้รับการป้องกัน = "แอตทริบิวต์ลูกชาย"; สตริงสาธารณะ getName () {ชื่อคืน; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {พ่อตัวอย่าง = ลูกชายคนใหม่ (); System.out.println ("เรียกว่าคุณสมบัติ:" + sample.getName ()); - ผลลัพธ์: คุณลักษณะของลูกชายเรียกว่า
ทำไม Java จึงใช้วิธีการผูกมัดแบบคงที่สำหรับคุณลักษณะ? นี่เป็นเพราะการผูกมัดแบบคงที่มีประโยชน์มากมายซึ่งช่วยให้เราสามารถค้นพบข้อผิดพลาดในโปรแกรมในช่วงระยะเวลาการรวบรวมแทนที่จะเป็นช่วงเวลารันไทม์ สิ่งนี้จะปรับปรุงประสิทธิภาพการทำงานของโปรแกรม! การเชื่อมโยงแบบไดนามิกของวิธีการคือการใช้ polymorphism ซึ่งเป็นคุณสมบัติสำคัญของ Java Polymorphism ยังเป็นหนึ่งในเทคโนโลยีที่มุ่งเน้นวัตถุสำคัญดังนั้นจึงคุ้มค่าสำหรับ Java ที่จะใช้ polymorphism ในราคาที่มีประสิทธิภาพ
หมายเหตุ: เนื้อหาส่วนใหญ่ข้างต้นมาจากอินเทอร์เน็ตและส่วนเล็ก ๆ เป็นความเห็นส่วนตัวและไม่ได้หมายถึงคำพูดที่เชื่อถือได้ หากมีภาษาที่ไม่เหมาะสมหรือการแสดงออกที่ไม่ถูกต้องฉันหวังว่าจะให้คำแนะนำแก่คุณ
ขอบคุณสำหรับการอ่านฉันหวังว่ามันจะช่วยคุณได้ ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!