เพื่อให้เข้าใจถึงหลักการของการไตร่ตรองคุณต้องเข้าใจก่อนว่าประเภทของข้อมูลคืออะไร Java ช่วยให้เราสามารถระบุข้อมูลของวัตถุและคลาสได้ที่รันไทม์ และมีสองวิธีหลัก: หนึ่งคือ RTTI แบบดั้งเดิมซึ่งสันนิษฐานว่าเรารู้ข้อมูลทุกประเภทในเวลาคอมไพล์แล้ว อีกอย่างคือกลไกการสะท้อนกลับซึ่งช่วยให้เราสามารถค้นพบและใช้ข้อมูลของคลาสที่รันไทม์
1. วัตถุคลาส
เพื่อให้เข้าใจว่า RTTI ทำงานอย่างไรใน Java คุณต้องทราบวิธีการพิมพ์ข้อมูลประเภทที่รันไทม์อย่างไร สิ่งนี้ทำโดยวัตถุคลาสซึ่งมีข้อมูลที่เกี่ยวข้องกับคลาส วัตถุคลาสถูกใช้เพื่อสร้างวัตถุ "ปกติ" ทั้งหมด Java ใช้วัตถุคลาสเพื่อดำเนินการ RTTI แม้ว่าคุณจะดำเนินการเช่นการแปลงประเภท
แต่ละคลาสจะสร้างวัตถุคลาสที่สอดคล้องกันซึ่งบันทึกไว้ในไฟล์. class คลาสทั้งหมดจะถูกโหลดแบบไดนามิกไปยัง JVM เมื่อใช้เป็นครั้งแรก คลาสนี้จะถูกโหลดเมื่อโปรแกรมสร้างการอ้างอิงไปยังสมาชิกคงที่ของชั้นเรียน วัตถุคลาสจะถูกโหลดเฉพาะเมื่อจำเป็นและการเริ่มต้นแบบคงที่จะดำเนินการเมื่อโหลดคลาส
Public Class Testmain {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {system.out.println (xyz.name);}} คลาส xyz {ชื่อสตริงคงที่สาธารณะ = "luoxn28"; คงที่ {system.out.println ("xyz static block"); สร้าง ");}}ผลลัพธ์ผลลัพธ์คือ:
ตัวโหลดคลาสก่อนตรวจสอบว่าวัตถุคลาสของคลาสนี้ได้รับการโหลดหรือไม่ หากยังไม่ได้รับการโหลดตัวโหลดคลาสเริ่มต้นจะค้นหาไฟล์. class ที่สอดคล้องกันตามชื่อคลาส
ในการใช้ข้อมูลประเภทที่รันไทม์คุณต้องได้รับการอ้างอิงไปยังคลาสคลาสของวัตถุ (เช่นวัตถุพื้นฐาน) คุณสามารถใช้ function class.forname ("ฐาน") เพื่อให้ได้สิ่งนี้หรือใช้ base.class โปรดทราบว่ามันน่าสนใจ เมื่อใช้ฟังก์ชั่น ".class" เพื่อสร้างการอ้างอิงไปยังวัตถุคลาสวัตถุคลาสจะไม่เริ่มต้นโดยอัตโนมัติและการใช้ชื่อ forname () จะเริ่มต้นวัตถุคลาสโดยอัตโนมัติ การเตรียมการสำหรับการใช้คลาสโดยทั่วไปมี 3 ขั้นตอนต่อไปนี้:
•การโหลด: เสร็จสิ้นโดยคลาสโหลดเดอร์ค้นหา bytecode ที่สอดคล้องกันและสร้างวัตถุคลาส
•ลิงก์: ตรวจสอบ bytecode ในคลาสและจัดสรรพื้นที่สำหรับโดเมนคงที่
•การเริ่มต้น: หากคลาสมี superclass มันจะเริ่มต้นและการเริ่มต้นแบบคงที่และบล็อกการเริ่มต้นแบบคงที่จะถูกดำเนินการ
ฐานสาธารณะคลาส {คงที่ int num = 1; Static {System.out.println ("base" + num);}} คลาสสาธารณะหลัก {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {// บล็อกคงที่จะไม่เริ่มต้นคลาส clazz1 = base.class; system.out.out.out.println ("------"); class.forName ("zzz.base");}} 2. ตรวจสอบก่อนการแปลงพิมพ์
คอมไพเลอร์จะตรวจสอบว่าการเปลี่ยนประเภทลงตามกฎหมายหรือไม่และหากไม่ถูกกฎหมายจะมีข้อยกเว้นจะถูกโยนลงไป ก่อนที่จะแปลงประเภทลงคุณสามารถใช้อินสแตนซ์ของการตัดสิน
คลาสฐาน {} คลาสที่ได้รับขยายฐาน {} คลาสสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {base base = new derived (); ถ้า (พื้นฐานที่ได้มา) {// ที่นี่คุณสามารถลงระบบลงได้ 3. การสะท้อน: ข้อมูลรันไทม์
หากคุณไม่ทราบประเภทของวัตถุที่แน่นอน RTTI สามารถบอกคุณได้ แต่มีข้อกำหนดเบื้องต้น: ประเภทนี้จะต้องเป็นที่รู้จักในเวลารวบรวมเพื่อให้สามารถใช้ RTTI เพื่อระบุได้ คลาสคลาสรองรับการสะท้อนพร้อมกับ java.lang.reflect library ไลบรารีคลาสนี้มีฟิลด์เมธอดและคลาสคอนสตรัคเตอร์ วัตถุของคลาสเหล่านี้ถูกสร้างขึ้นโดย JVM เมื่อเริ่มต้นเพื่อเป็นตัวแทนของสมาชิกที่เกี่ยวข้องในคลาสที่ไม่รู้จัก ด้วยวิธีนี้คุณสามารถใช้ตัวดัดแปลงเพื่อสร้างวัตถุใหม่ใช้วิธีการรับ () และ set () เพื่อรับและแก้ไขฟิลด์ที่เกี่ยวข้องกับวัตถุฟิลด์ในคลาสและใช้เมธอด Invoke () เพื่อเรียกวิธีการที่เกี่ยวข้องกับวัตถุวิธี นอกจากนี้วิธีการที่สะดวกหลายอย่างเช่น getFields (), getMethods () และ getConstructors () ยังสามารถเรียกได้เพื่อส่งคืนอาร์เรย์ที่เป็นตัวแทนของฟิลด์วิธีการและวัตถุสร้าง ด้วยวิธีนี้ข้อมูลวัตถุสามารถกำหนดได้อย่างสมบูรณ์ในเวลาทำงานโดยไม่ทราบอะไรเกี่ยวกับชั้นเรียนในเวลาที่รวบรวม
ไม่มีอะไรมหัศจรรย์เกี่ยวกับกลไกการสะท้อน เมื่อจัดการกับวัตถุประเภทที่ไม่รู้จักผ่านการสะท้อน JVM เพียงตรวจสอบวัตถุเพื่อดูคลาสเฉพาะที่เป็นของ ดังนั้น. class ของคลาสนั้นจะต้องสามารถเรียกได้สำหรับ JVM ไม่ว่าจะเป็นในเครื่องท้องถิ่นหรือจากเครือข่าย ดังนั้นความแตกต่างที่แท้จริงระหว่าง RTTI และการสะท้อนจึงเป็นเพียง:
• RTTI คอมไพเลอร์จะเปิดและตรวจสอบไฟล์. class ในเวลาคอมไพล์
•ไตร่ตรองเปิดและตรวจสอบไฟล์คลาสที่รันไทม์
บุคคลระดับสาธารณะใช้ serializable {ชื่อสตริงส่วนตัว; อายุ int ส่วนตัว; // get/set method} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {บุคคลบุคคล = บุคคลใหม่ ("luoxn28", 23); class clazz = person.getClass () ฟิลด์ descriptor = ใหม่ PropertyDescriptor (คีย์, clazz); วิธีการ = descriptor.getReadMethod (); ค่าวัตถุ = method.invoke (บุคคล); system.out.println (key + ":" + value);}}} การเรียกข้างต้นฟังก์ชัน GET ของคลาสผ่านวิธี getReadMethod () และวิธี getWriteMethod () สามารถใช้เรียกวิธีการตั้งค่าของคลาส โดยทั่วไปแล้วเราไม่จำเป็นต้องใช้เครื่องมือสะท้อนแสง แต่มีประโยชน์มากกว่าในการสร้างรหัสไดนามิก การสะท้อนกลับใช้ใน Java เพื่อรองรับคุณสมบัติอื่น ๆ เช่นการทำให้เป็นอนุกรมวัตถุและ Javabeans
4. ตัวแทนไดนามิก
โหมดพร็อกซีคือการให้การดำเนินการเพิ่มเติมหรือแตกต่างกันและวัตถุที่แทรกถูกใช้เพื่อแทนที่วัตถุ "จริง" ซึ่งเกี่ยวข้องกับการสื่อสารกับวัตถุ "จริง" ดังนั้นพร็อกซีมักจะทำหน้าที่เป็นตัวกลาง พร็อกซีแบบไดนามิกของ Java เป็นก้าวหนึ่งก้าวไปข้างหน้าของแนวคิดของพร็อกซีซึ่งสามารถสร้างและพร็อกซีแบบไดนามิกและจัดการการโทรไปยังวิธีพร็อกซีแบบไดนามิก การโทรทั้งหมดที่ทำในพร็อกซีแบบไดนามิกจะถูกเปลี่ยนเส้นทางไปยังโปรเซสเซอร์การโทรเพียงครั้งเดียวและงานของมันคือการเปิดเผยประเภทของการโทรและกำหนดนโยบายที่เกี่ยวข้อง นี่คือตัวอย่างของพร็อกซีแบบไดนามิก:
คลาสอินเตอร์เฟสและการใช้งาน:
อินเตอร์เฟสสาธารณะส่วนต่อประสาน {โมฆะ dosomething (); เป็นโมฆะ Somethingelse (String arg);} คลาสสาธารณะ realobject ใช้อินเทอร์เฟซ {โมฆะสาธารณะ dosomething () {system.out.println ("dosomething."); โปรเซสเซอร์วัตถุพร็อกซีแบบไดนามิก:
คลาสสาธารณะ DynamicProxyHandler ใช้ InvocationHandler {วัตถุส่วนตัว proxyed; DynamicProxyHandler สาธารณะ (วัตถุพร็อกซี) {this.proxyed = proxyed;}@overridepublic object revoke (object proxy, วิธีการ, วัตถุ [] พร็อกซีกำลังทำงาน "); วิธีการส่งคืน invoke (proxyed, args);}} คลาสทดสอบ:
คลาสสาธารณะ Main {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {realobject real = new realobject (); อินเตอร์เฟส proxy = (อินเตอร์เฟส) proxy.newproxyinstance (interface.class.getclassloader () คลาสใหม่ [] {interface.class}, ใหม่ DynamicProxyHandler (ของจริง)); proxy.dosomething (); proxy.somethingelse ("luoxn28");}}ผลลัพธ์ผลลัพธ์มีดังนี้:
คุณสามารถสร้างพร็อกซีแบบไดนามิกได้โดยการเรียกพร็อกซีวิธีการคงที่ proxy.newproxyinstance () วิธีนี้ต้องใช้ตัวโหลดคลาสรายการของอินเทอร์เฟซที่คุณต้องการให้พร็อกซีใช้งาน (ไม่ใช่คลาสหรือคลาสนามธรรม) และคลาสการใช้งานของ InvocationHandler พร็อกซีแบบไดนามิกสามารถเปลี่ยนเส้นทางการโทรทั้งหมดไปยังโปรเซสเซอร์การโทรได้ดังนั้นตัวสร้างของโปรเซสเซอร์การโทรมักจะผ่านการอ้างอิงไปยังวัตถุ "จริง" ซึ่งจะส่งต่อคำขอเมื่อโปรเซสเซอร์การโทรดำเนินงานการไกล่เกลี่ย
ข้างต้นคือความเข้าใจในเชิงลึกของการสะท้อน Java ที่แนะนำโดยบรรณาธิการให้คุณ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!