1. RTTI:
ข้อมูลประเภทรันไทม์ช่วยให้คุณค้นพบและใช้ข้อมูลประเภทในขณะที่โปรแกรมกำลังทำงานอยู่
มีสองวิธีในการระบุข้อมูลเกี่ยวกับวัตถุและคลาสเมื่อทำงานใน Java: RTTI แบบดั้งเดิมและการสะท้อนกลับ มาพูดถึง RTTI กันเถอะ
RTTI: ที่รันไทม์ระบุประเภทของวัตถุ แต่ประเภทนี้จะต้องเป็นที่รู้จักในเวลาคอมไพล์
ลองมาเป็นตัวอย่างเพื่อดูการใช้ RTTI สิ่งนี้เกี่ยวข้องกับแนวคิดของ polymorphism: การปล่อยให้รหัสใช้งานเฉพาะในการอ้างอิงไปยังคลาสฐานและวิธีการเรียกใช้คลาสย่อยเฉพาะมักจะสร้างวัตถุคอนกรีต (วงกลมสี่เหลี่ยมหรือสามเหลี่ยมดูตัวอย่างด้านล่าง) เปลี่ยนรูปแบบให้เป็นรูปร่าง
บทคัดย่อคลาสคลาส {// นี้เรียกวิธีการ toString () ของคลาสปัจจุบันโดยส่งคืนเนื้อหาที่เป็นโมฆะการวาด () {system.out.println (this + "draw ()"); } // ประกาศ toString () เป็นประเภทนามธรรมการรวมพลังเพื่อแทนที่วิธีการนามธรรมสตริงสาธารณะ toString ();} วงกลมคลาสขยายรูปร่าง {สตริงสาธารณะ toString () {return "circle"; }} คลาสสแควร์ขยายรูปร่าง {สตริงสาธารณะ toString () {return "square"; }} ชั้นเรียนสามเหลี่ยมขยายรูปร่าง {สตริงสาธารณะ toString () {return "สามเหลี่ยม"; }} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// เมื่อใส่วัตถุรูปร่างลงในอาร์เรย์ของรายการ <mhape> มันจะเปลี่ยนเป็นรูปร่างขึ้นไปดังนั้นจึงสูญเสียรายการข้อมูลประเภทเฉพาะ <shape> shapelist = array.aslist (วงกลมใหม่ (), New Square (), ใหม่ // เมื่อนำออกจากอาร์เรย์ในความเป็นจริงองค์ประกอบทั้งหมดของคอนเทนเนอร์นี้จะถูกเก็บเป็นวัตถุและจะแปลงผลลัพธ์เป็นรูปร่างโดยอัตโนมัติ นี่คือการใช้ RTTI ขั้นพื้นฐาน สำหรับ (รูปร่างรูปร่าง: shapelist) {shape.draw (); -ผลลัพธ์ผลลัพธ์คือ:
Circledraw () Squaredraw () Triangledraw ()
เมื่อฝากไว้ในอาร์เรย์มันจะเปลี่ยนเป็นรูปร่างโดยอัตโนมัติและประเภทเฉพาะจะหายไป เมื่อนำออกจากอาร์เรย์ (รายการคอนเทนเนอร์เก็บทุกอย่างเป็นวัตถุ) มันจะแปลงผลลัพธ์กลับเป็นรูปร่างโดยอัตโนมัติ นี่คือการใช้งานพื้นฐานของ RTTI การแปลงประเภททั้งหมดใน Java ได้รับการตรวจสอบการแก้ไขที่รันไทม์นั่นคือ RTTI: ที่รันไทม์ระบุประเภทของวัตถุ
การเปลี่ยนแปลงข้างต้นไม่ได้ละเอียด เมื่อองค์ประกอบของอาร์เรย์ถูกนำออกวัตถุจะถูกเปลี่ยนเป็นรูปร่างไม่ใช่ประเภทเฉพาะ สิ่งนี้ทำโดยคอนเทนเนอร์และระบบ Java Generic ในระหว่างการรวบรวมและมีการดำเนินการแปลงประเภทเพื่อให้แน่ใจว่าสิ่งนี้ในรันไทม์
รหัสเฉพาะที่สามารถดำเนินการลงในคลาสย่อยผ่านวัตถุรูปร่างถูกกำหนดโดย polymorphism สำหรับรายละเอียดมันขึ้นอยู่กับวัตถุเฉพาะที่ชี้ไปโดยการอ้างอิงรูปร่าง
นอกจากนี้การใช้ RTTI คุณสามารถสืบค้นประเภทที่แน่นอนของวัตถุที่ชี้ไปที่การอ้างอิงรูปร่างจากนั้นเลือกใช้วิธี subclass
2. วัตถุคลาส:
เพื่อให้เข้าใจว่า RTTI ทำงานอย่างไรใน Java คุณต้องรู้ว่าข้อมูลประเภทแสดงถึงวิธีรันไทม์ซึ่งทำโดยคลาสวัตถุพิเศษ
วัตถุคลาสถูกใช้เพื่อสร้างวัตถุ "ปกติ" ทั้งหมดของคลาส Java ใช้วัตถุคลาสเพื่อดำเนินการ RTTI
เมื่อใดก็ตามที่มีการรวบรวมคลาสใหม่วัตถุคลาส (. class ไฟล์) จะถูกสร้างขึ้น JVM ที่รันโปรแกรมนี้จะใช้ระบบย่อย "คลาสโหลดเดอร์"
ระบบย่อยตัวโหลดคลาส: มีโซ่ตัวโหลดคลาส แต่มีเพียงตัวโหลดคลาสเนทีฟเดียวซึ่งเป็นส่วนหนึ่งของการใช้งาน JVM โหลดคลาสดั้งเดิมโหลดคลาสที่เชื่อถือได้รวมถึงคลาส Java API ซึ่งมักจะมาจากดิสก์ท้องถิ่น เมื่อต้องมีการโหลดคลาสด้วยวิธีการบางอย่างเพื่อรองรับแอปพลิเคชันเว็บเซิร์ฟเวอร์สามารถแนบตัวโหลดคลาสเพิ่มเติมได้
2.1. เวลาในการโหลดคลาส:
คลาสนี้จะถูกโหลดเมื่อโปรแกรมสร้างการอ้างอิงครั้งแรกไปยังสมาชิกคงที่ของคลาส นี่เป็นการพิสูจน์ว่าตัวสร้างเป็นวิธีการคงที่ของชั้นเรียน เมื่อสร้างวัตถุใหม่ของคลาสโดยใช้ตัวดำเนินการใหม่มันจะถูกใช้เป็นข้อมูลอ้างอิงถึงสมาชิกคงที่ของคลาส
จะเห็นได้ว่าโปรแกรม Java ถูกโหลดแบบไดนามิกและโหลดตามความต้องการ เมื่อจำเป็นต้องเรียนคลาสโหลดเดอร์จะตรวจสอบก่อนว่าวัตถุคลาสของคลาสนี้ได้รับการโหลดหรือไม่ หากยังไม่ได้รับการโหลดตัวโหลดคลาสเริ่มต้นจะพบไฟล์. class ตามชื่อคลาส ถัดไปคือขั้นตอนการตรวจสอบ: เมื่อโหลดพวกเขายอมรับการตรวจสอบเพื่อให้แน่ใจว่าพวกเขาจะไม่เสียหายและไม่มีรหัส Java ที่ไม่ดี
2.2. วิธีการที่เกี่ยวข้องกับคลาส, Newinstance ()
ต่อไปนี้เป็นตัวอย่างในการแสดงการโหลดของวัตถุคลาส:
คลาส A {// ฐานรหัสคงที่ดำเนินการเมื่อโหลดเป็นครั้งแรกและเป็นที่รู้จักเมื่อคลาสถูกโหลดโดยการพิมพ์ข้อมูลคงที่ {system.out.println ("โหลด A"); }} คลาส B {Static {System.out.println ("โหลด b"); }} คลาส C {Static {System.out.println ("โหลด C"); }} การโหลดคลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {system.out.println ("ดำเนินการหลัก ... "); ใหม่ A (); System.out.println ("After New A"); ลอง {class.forname ("com.itzhai.test.type.b"); } catch (classnotfoundexception e) {system.out.println ("คลาวด์ไม่พบคลาส B"); } system.out.println ("หลังคลาส forname b"); ใหม่ C (); System.out.println ("After New C"); -ผลลัพธ์ผลลัพธ์คือ:
ดำเนินการหลัก ... กำลังโหลด aafter ใหม่ aloading bafter class.forname bloading cafter ใหม่ c
จะเห็นได้ว่าวัตถุคลาสจะถูกโหลดเฉพาะเมื่อจำเป็น หมายเหตุเมธอด class.forname () ที่นี่:
วิธีการ forname () เป็นวิธีที่จะได้รับการอ้างอิงไปยังวัตถุคลาส โดยการได้รับการอ้างอิงที่เหมาะสมไปยังวัตถุคลาสคุณสามารถใช้ข้อมูลประเภทที่รันไทม์
หากคุณมีวัตถุที่น่าสนใจอยู่แล้วคุณสามารถรับการอ้างอิงคลาสได้โดยทำตามวิธี getClass () ที่จัดทำโดยวัตถุคลาส
นี่คือรหัสที่ใช้โดยคลาส:
อินเตอร์เฟส x {} อินเตอร์เฟส y {} อินเตอร์เฟส z {} ตัวอักษรคลาส {ตัวอักษร () {}; ตัวอักษร (int i) {};} คลาส newletter ขยายตัวอักษรใช้เครื่องมือ x, y, z {newletter () {super (1); };} คลาสสาธารณะ Classtest { / *** ข้อมูลประเภทพิมพ์* @param c* / โมฆะคงที่ printinfo (คลาส C) {// getName () ได้รับชื่อคลาสที่ผ่านการรับรองอย่างสมบูรณ์ system.out.println ("ชื่อคลาส:" + c.getName () + " // รับชื่อคลาส System.out.println ("ชื่อง่าย:" + C.GetSimplename ()); // รับชื่อคลาสที่ผ่านการรับรองอย่างสมบูรณ์ system.out.println ("ชื่อที่เป็นที่ยอมรับ:" + C.GetCanonicalName ()); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {class c = null; ลอง {// รับการอ้างอิงคลาส c = class.forname ("com.itzhai.test.type.newletter"); } catch (classnotfoundexception e) {system.out.println ("ไม่พบ com.itzhai.test.type.newletter"); System.Exit (1); } // พิมพ์ข้อมูลประเภทอินเตอร์เฟสสำหรับ (คลาสหน้า: c.getInterfaces ()) {printinfo (ใบหน้า); } // รับคลาสอ้างอิงคลาส SuperClass ขึ้น = C.GetSuperClass (); วัตถุ obj = null; ลอง {// สร้างอินสแตนซ์ของคลาสผ่านเมธอด newInstance () obj = up.newinstance (); } catch (InstantiationException e) {system.out.println ("ไม่สามารถสร้างอินสแตนซ์"); } catch (unglemalAccessException e) {system.out.println ("ไม่สามารถเข้าถึงได้"); } // พิมพ์ข้อมูลประเภท superclass printinfo (obj.getClass ()); -ผลลัพธ์คือ:
ชื่อคลาส: com.itzhai.test.type.x เป็นอินเตอร์เฟสหรือไม่? ชื่อ truesimple: xcanonical ชื่อ: com.itzhai.test.type.xclass ชื่อ: com.itzhai.test.type.y เป็นอินเตอร์เฟสหรือไม่? ชื่อ truesimple: ycanonical ชื่อ: com.itzhai.test.type.yclass ชื่อ: com.itzhai.test.type.z เป็นอินเทอร์เฟซหรือไม่? ชื่อ truesimple: zcanonical ชื่อ: com.itzhai.test.type.zclass ชื่อ: com.itzhai.test.type.letter เป็นอินเตอร์เฟสหรือไม่? ชื่อ Falsesimple: Lettercanonical ชื่อ: com.itzhai.test.type.letter
โปรดทราบว่าสตริงที่ส่งผ่านไปยังชื่อ forname () จะต้องใช้ชื่อที่ผ่านการรับรองอย่างสมบูรณ์ (รวมถึงชื่อแพ็คเกจ)
ผ่านวิธีการที่ใช้ใน PrintInfo คุณสามารถค้นพบโครงสร้างการสืบทอดคลาสที่สมบูรณ์ของวัตถุที่รันไทม์
ด้วยการใช้เมธอด newInstance () ของคลาสมันเป็นวิธีที่จะใช้ "ตัวสร้างเสมือน" เพื่อสร้างอินสแตนซ์ของคลาส ได้รับการอ้างอิงวัตถุ แต่ชี้ไปที่วัตถุตัวอักษรเมื่ออ้างอิง คลาสที่สร้างขึ้นโดยใช้ newInstance () ต้องมีตัวสร้างเริ่มต้น (ผ่านการสะท้อน API คุณสามารถใช้ตัวสร้างใด ๆ เพื่อสร้างวัตถุคลาสแบบไดนามิก)
2.3. ค่าคงที่ตัวอักษรชั้นเรียน:
นอกเหนือจากการใช้วิธี getName () แล้ว Java ยังให้อีกวิธีหนึ่งในการสร้างการอ้างอิงไปยังวัตถุคลาสนั่นคือการใช้ค่าคงที่ตัวอักษรคลาส:
newletter.class;
วิธีนี้ง่ายและปลอดภัยและถูกตรวจสอบในระหว่างการรวบรวมทำให้มีประสิทธิภาพมากขึ้น มันสามารถใช้ไม่เพียง แต่สำหรับคลาสทั่วไป แต่ยังสำหรับอินเทอร์เฟซอาร์เรย์และประเภทข้อมูลพื้นฐาน นอกจากนี้สำหรับคลาส wrapper ของประเภทข้อมูลพื้นฐานนอกจากนี้ยังมีประเภทฟิลด์มาตรฐาน ฟิลด์ Type เป็นการอ้างอิงเพื่อดำเนินการวัตถุคลาสข้อมูลพื้นฐานที่สอดคล้องกัน เพื่อประโยชน์ของการรวมกันขอแนะนำให้ใช้แบบฟอร์ม. คลาส
2.4. ความแตกต่างระหว่างการใช้. class และการใช้วิธี getName () เพื่อสร้างการอ้างอิงวัตถุ:
เมื่อสร้างด้วย. class วัตถุคลาสจะไม่เริ่มต้นโดยอัตโนมัติ ขั้นตอนการสร้างมีดังนี้:
(1) การโหลดจะดำเนินการโดยคลาสโหลดเดอร์: ค้นหา bytecode (โดยปกติจะอยู่ในเส้นทางที่ระบุโดย classpath แต่ไม่จำเป็น) จากนั้นสร้างวัตถุคลาสจากไบต์เหล่านี้
(2) ลิงค์จะตรวจสอบไบต์ในคลาสและจัดสรรพื้นที่เก็บข้อมูลสำหรับโดเมนคงที่ หากจำเป็นการอ้างอิงทั้งหมดไปยังคลาสอื่น ๆ ที่สร้างโดยคลาสนี้จะถูกแยกวิเคราะห์
(3) การเริ่มต้นหากคลาสมี superclass เริ่มต้นมันและดำเนินการเริ่มการเริ่มต้นแบบคงที่และบล็อกการเริ่มต้นแบบคงที่
การเริ่มต้นล่าช้าจนกว่าการอ้างอิงครั้งแรกไปยังวิธีการคงที่ (ตัวสร้างเป็นแบบคงที่โดยปริยาย) หรือโดเมนคงที่ไม่ใช่จำนวน:
คลาส data1 {int สุดท้ายคงที่ a = 1; คงที่ double double b = math.random (); Static {System.out.println ("init data1 ... "); }} คลาส data2 {int คงที่ a = 12; Static {System.out.println ("init data2 ... "); }} คลาส data3 {int คงที่ a = 23; Static {System.out.println ("init data3 ... "); }} คลาสสาธารณะ classtest2 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {system.out.println ("data1.class:"); คลาส data1 = data1.class; System.out.println (data1.a); // data1 system.out.println (data1.b); // DATA1 Initialized System.out.println (data2.a); // data2 เริ่มต้นลอง {class data3 = class.forName ("com.itzhai.test.type.data3"); // data3 เริ่มต้น} catch (classnotfoundexception e) {system.out.println ("ไม่พบ com.itzhai.test.type.data3 ... "); } system.out.println (data3.a); -ผลลัพธ์ผลลัพธ์คือ:
data1.class: 1init data1 ... 0.26771085109184534init data2 ... 12init data3 ... 23
การเริ่มต้นประสบความสำเร็จอย่างมีประสิทธิภาพในฐานะ "ขี้เกียจ" มากที่สุด
2.5. ต่อไปนี้เป็นสถานการณ์บางอย่างสำหรับการพิจารณาว่าจะทำการเริ่มต้นหรือไม่:
(1) ไวยากรณ์คลาสได้รับการอ้างอิงไปยังชั้นเรียนและจะไม่ทำให้เกิดการเริ่มต้น
(2) class.forName () สร้างการอ้างอิงคลาสและเริ่มต้นทันที
(3) หากค่าสุดท้ายคงที่คือ "ค่าคงที่คอมไพเลอร์" ค่านี้สามารถอ่านได้โดยไม่ต้องเริ่มต้นคลาส
(4) มันไม่เพียงพอที่จะตรวจสอบพฤติกรรมนี้หากเพียงแค่ตั้งค่าโดเมนเป็นขั้นสุดท้ายคงที่ตัวอย่างเช่น:
คงที่ double double b = math.random ();
(5) หากโดเมนคงที่เป็น bushifinal ดังนั้นเมื่อเข้าถึงได้คุณจะต้องเชื่อมโยงขั้นสูงและเริ่มต้น
2.6. ใบเสนอราคาชั้นเรียนทั่วไป:
การอ้างอิงคลาสแสดงถึงประเภทที่แน่นอนของวัตถุที่ชี้ไปที่และวัตถุเป็นวัตถุของคลาสคลาส ใน Javase5 วัตถุคลาสที่ชี้ไปที่การอ้างอิงคลาสสามารถผ่านการรับรองโดยทั่วไปและคอมไพเลอร์สามารถบังคับใช้การตรวจสอบประเภทเพิ่มเติม:
คลาส intcls = int.class; // ใช้ยาชื่อสามัญเพื่อกำหนดอ้างอิงที่ชี้ไปที่คลาสคลาส <teger> genintcls = int.class; // คลาสที่ไม่มีทั่วไปสามารถกำหนดใหม่เพื่อชี้ไปที่วัตถุคลาสอื่น ๆ intcls = double.class; // การรวบรวมต่อไปนี้
2.6.1. ใช้ไวด์การ์ด? ผ่อนคลายข้อ จำกัด ของยาสามัญ:
คลาส <?> intcls = int.class; intcls = string.class;
ใน Javase5 คลาส <?> ดีกว่าคลาสธรรมดาและแนะนำให้ใช้คลาส <?> แม้ว่าพวกเขาจะเทียบเท่าเพราะข้อดีของคลาส <?> นั่นหมายความว่าคุณไม่ได้เกิดขึ้นหรือประมาท แต่ใช้การอ้างอิงคลาสที่ไม่เฉพาะเจาะจง
ในการกำหนดการอ้างอิงถึงคลาสเป็นประเภทหนึ่งหรือชนิดย่อยของประเภทนั้นสามารถใช้ไวด์การ์ดกับขยายสร้างขอบเขต:
ชั้นเรียน <? ขยายหมายเลข> num = int.class; // ช่วงการอ้างอิงของ num คือหมายเลขและ subclass ของมันดังนั้นคุณสามารถกำหนดค่า num = double.class; num = number.class;
2.6.2. เมธอด newinstance () ภายใต้ทั่วไป:
การใช้คลาสหลังจากทั่วไปวัตถุที่ส่งคืนโดยการเรียก newinstance () เป็นประเภทที่แน่นอน แต่เมื่อคุณใช้ getSuperclass () เพื่อให้ได้ superclass ที่สอดคล้องกับทั่วไปมีข้อ จำกัด บางประการสำหรับประเภทจริง: คอมไพเลอร์รู้ประเภทของ superclass ในช่วงเวลาการรวบรวม
Dog Dog = dogcls.newinstance (); Abstract Class Animal {} Class Dog ขยายสัตว์ {} // วิธีการเขียนต่อไปนี้ไม่ถูกต้องและสามารถคืนคลาส <? Super Dog> Type // class <mimant> AnimalCls = dogcls.getsuperclass (); ชั้นเรียน <? Super Dog> AnimalCls = dogcls.getsuperclass (); // ผ่านการอ้างอิง superclass ที่ได้รับคุณสามารถสร้างวัตถุที่ส่งคืนวัตถุประเภทวัตถุ OBJ = AnimalCls.NewInstance (); 2.6.3. ใหม่การแปลงไวยากรณ์: cast () วิธีการ
ดูรหัสโดยตรง:
สัตว์สัตว์ = สุนัขใหม่ (); คลาส <dog> dogcls = dog.class; dog dog = dogcls.cast (สัตว์); // หรือใช้วิธีการเปลี่ยนแปลงโดยตรงต่อไปนี้สุนัข = (สุนัข) สัตว์;
สามารถพบได้ว่าการใช้วิธี Cast () ได้ทำงานเพิ่มเติม วิธีการแปลงนี้สามารถใช้ในสถานการณ์ต่อไปนี้: เมื่อเขียนวงดนตรีทั่วไปหากการอ้างอิงคลาสถูกเก็บไว้และคุณหวังว่าจะทำการแปลงผ่านการอ้างอิงคลาสนี้คุณสามารถใช้วิธี Cast ()
3. พิมพ์อินสแตนซ์ของ
3.1. ตรวจสอบก่อนการแปลงพิมพ์
คอมไพเลอร์ช่วยให้คุณสามารถดำเนินการการกำหนดการแปลงที่เพิ่มขึ้นได้อย่างอิสระโดยไม่ต้องดำเนินการแปลงที่แสดงเช่นเดียวกับการกำหนดค่าให้กับการอ้างอิงถึงซูเปอร์คลาส
อย่างไรก็ตามหากไม่ได้ใช้การแปลงประเภทที่แสดงคอมไพเลอร์จะไม่อนุญาตให้คุณทำการกำหนดแบบ downconversion ในเวลานี้เราอาจตรวจสอบว่าวัตถุนั้นเป็นอินสแตนซ์ของประเภทเฉพาะและอินสแตนซ์คำหลักของคำหลัก:
ถ้า (x อินสแตนซ์ของสุนัข) ((สุนัข) x) .Bark ();
3.2. รูปแบบของ rtti:
จนถึงตอนนี้เรารู้ว่ารูปแบบของ RTTI รวมถึง:
(1) การแปลงแบบดั้งเดิม (รูปร่าง)
(2) วัตถุคลาสแสดงประเภทของวัตถุ
(3) คำหลักอินสแตนซ์ของ
3.3. อินสแตนซ์แบบไดนามิกของวิธี:
วิธีการคลาส Isinstance ให้วิธีการทดสอบวัตถุแบบไดนามิก
ต่อไปนี้แสดงให้เห็นถึงการใช้งานอินสแตนซ์และ class.isinstance:
คุณลักษณะ:
แอตทริบิวต์ส่วนต่อประสานสาธารณะ {}รูปร่าง:
/** * สร้างคลาสบทคัดย่อ */รูปทรงคลาสนามธรรมสาธารณะ {// สิ่งนี้เรียกวิธีการ toString ของวิธี toString คลาสปัจจุบันเพื่อให้ได้ข้อมูลโมฆะสาธารณะ draw () {system.out.println (this + ".draw ()"); } // ประกาศวิธี TOSTRING () เป็นนามธรรมดังนั้นจึงบังคับให้ผู้สืบทอดเขียนวิธีการใหม่ บทคัดย่อสตริงสาธารณะ toString ();}วงกลม:
วงกลมระดับสาธารณะขยายคุณสมบัติการใช้งาน {สตริงสาธารณะ toString () {return "circle"; -สี่เหลี่ยม:
สแควร์ระดับสาธารณะขยายรูปร่าง {สตริงสาธารณะ toString () {return "square"; -สามเหลี่ยม:
รูปสามเหลี่ยมระดับสาธารณะขยายรูปร่าง {สตริงสาธารณะ toString () {return "สามเหลี่ยม"; -ประเภทการตรวจสอบ:
// instanceofcircle c = new circle (); // กำหนดว่าอินสแตนซ์ของ superclass system.out.format ("การใช้อินสแตนซ์ของ: %s เป็นรูปร่างหรือไม่? SuperClass System.out.format ("ใช้ class.isinstance: %s คือรูปร่าง? %b/n", c.toString (), c อินสแตนซ์วงกลม c); // พิจารณาว่าอินสแตนซ์ของ superclass system.out.out.OUT ("การใช้ class.Isinstance: %s เป็นรูปตัว? %b/n" System.out.format ("ใช้ class.isinstance: %s เป็นแอตทริบิวต์หรือไม่ %b/n", c.toString (), attribute.class.isinstance (c));สามารถพบได้ว่าวิธีการของ isinstance หรือ class.isinstance กำหนดว่าจะสืบทอดอินสแตนซ์ของระบบนั่นคือนอกเหนือจากการตัดสินตัวเองแล้วมันยังกำหนดว่ามันเป็น superclass หรืออินสแตนซ์ของอินเทอร์เฟซ
ต่อไปนี้แสดงให้เห็นถึงวิธีการใช้ Dynamic Class.Instance:
ก่อนอื่นสร้างคลาสเครื่องกำเนิดรูปร่างนามธรรม:
บทคัดย่อระดับสาธารณะ shapecreator {สุ่มส่วนตัว Rand = ใหม่สุ่ม (10); // ส่งคืนอาร์เรย์ของประเภทวัตถุที่จัดทำโดยคลาสการใช้งาน คุณจะเห็นแบบฟอร์มการใช้งานสองแบบในภายหลังโดยขึ้นอยู่กับชื่อและขึ้นอยู่กับค่าคงที่ตามตัวอักษรของชั้นเรียนรายการนามธรรมสาธารณะ <คลาส <? ขยายรูปร่าง >> ประเภท (); // สุ่มสร้างอินสแตนซ์วัตถุประเภทในอาร์เรย์ของประเภทวัตถุรูปร่างสาธารณะแบบสุ่ม () {int n = rand.nextint (ประเภท (). size ()); ลอง {type return (). get (n) .newinstance (); } catch (InstantiationException E) {E.printStackTrace (); คืนค่า null; } catch (unglegalAccessException e) {e.printStackTrace (); คืนค่า null; }} // สร้างรูปแบบสาธารณะแบบสุ่ม [] createArray (ขนาด int) {รูปร่าง [] ผลลัพธ์ = รูปร่างใหม่ [ขนาด]; สำหรับ (int i = 0; i <size; i ++) {result [i] = randomshape (); } ผลตอบแทนผลลัพธ์; } // สร้างอาร์เรย์แบบสุ่ม, ArrayList สาธารณะ arraylist ทั่วไป <mhape> arrayList (ขนาด int) {arrayList <mhape> result = new ArrayList <mhape> (); collections.addall (ผลลัพธ์, createarray (ขนาด)); ผลการกลับมา; -ถัดไปเขียนการใช้งานคลาสนามธรรมนี้:
/** * การใช้งาน ForName Generator * @author Artinking * */คลาสสาธารณะ fornamecreator ขยาย shapecreator {รายการคงที่ส่วนตัว <คลาส <? ขยายรูปร่าง >> ประเภท = arrayList ใหม่ <คลาส <? ขยายรูปร่าง >> (); สตริงคงที่ส่วนตัว [] typenames = {"com.itzhai.javanote.entity.circle", "com.itzhai.javanote.entity.square", "com.itzhai.javanote.entity.triangle"}; @SuppressWarnings ("ไม่ได้ใช้") โมฆะคงที่แบบคงที่ส่วนตัว () {สำหรับ (ชื่อสตริง: typenames) {ลอง {types.add ((คลาส <? ขยายรูปร่าง>) class.forname (ชื่อ)); } catch (classnotFoundException e) {e.printStackTrace (); }}} // เริ่มต้นอาร์เรย์ของประเภทที่จำเป็นสำหรับการโหลดแบบคงที่ {loader (); } รายการสาธารณะ <คลาส <? ขยายรูปร่าง >> ประเภท () {ประเภทคืน; -ในที่สุดเขียนคลาสที่นับจำนวนรูปร่างโดยใช้อินสแตนซ์ของ:
คลาสสาธารณะ shapecount {คลาสคงที่ Shapecounter ขยาย hashmap <string, integer> {นับโมฆะสาธารณะ (ประเภทสตริง) {ปริมาณจำนวนเต็ม = get (ประเภท); if (ปริมาณ == null) {put (type, 1); } else {put (ประเภท, ปริมาณ + 1); }}} // แสดงให้เห็นถึงประเภทวัตถุที่ระบุผ่านอินสแตนซ์ของคำหลักโมฆะโมฆะสาธารณะ countshapes (ผู้สร้าง shapecreator) {shapecounter counter = new Shapecounter (); สำหรับ (รูปร่างรูปร่าง: creator.createArray (20)) {ถ้า (รูปร่างของวงกลม) counter.count ("วงกลม"); ถ้า (รูปร่างอินสแตนซ์ของสแควร์) เคาน์เตอร์เคานต์ ("สแควร์"); if (รูปร่างของสามเหลี่ยม) {counter.count ("สามเหลี่ยม"); }} system.out.println (ตัวนับ); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {countshapes (ใหม่ fornameCreator ()); -เขียนใหม่การดำเนินการของคลาสนามธรรมและนำมาใช้ใหม่ด้วยค่าคงที่ตัวอักษรคลาส:
/*** การใช้งานเครื่องกำเนิดไฟฟ้าตามตัวอักษร*/LiteralCreator ระดับสาธารณะขยาย shapecreator {รายการสุดท้ายคงที่สาธารณะ <คลาส <? ขยายรูปร่าง >> allType = collections.unmodifiableList (array.aslist (circle.class, triangle.class, square.class)); รายการสาธารณะ <คลาส <? ขยายรูปร่าง >> ประเภท () {return AllType; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {system.out.println (AllType); -ตอนนี้ใช้ Class.Instance เพื่อนับจำนวนรูปร่างดังนี้:
/*** ลบคำสั่งอินสแตนซ์ monotonic ใน shapecount ดั้งเดิมโดยใช้ class.instanceof วัตถุทดสอบแบบไดนามิก**/คลาสสาธารณะ shapecount2 {รายการสุดท้ายคงที่ส่วนตัว <คลาส <? ขยายรูปร่าง >> spapetypes = literalCreator.allype; คลาสคงที่ Shapecounter ขยาย HashMap <String, Integer> {นับโมฆะสาธารณะ (ประเภทสตริง) {ปริมาณจำนวนเต็ม = รับ (ประเภท); if (ปริมาณ == null) {put (type, 1); } else {put (ประเภท, ปริมาณ + 1); }}} // แสดงให้เห็นถึงประเภทวัตถุสถิติผ่าน class.isinstance () โมฆะคงที่สาธารณะ countshapes (ผู้สร้าง Shapecreator) {Shapecounter Counter = New Shapecounter (); สำหรับ (รูปร่างรูปร่าง: creator.createArray (20)) {สำหรับ (คลาส <? ขยายรูปร่าง> cls: shapetypes) {ถ้า (cls.isinstance (รูปร่าง)) {counter.count (cls.getSimplename ()); }} system.out.println (ตัวนับ); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {countshapes (ใหม่ fornameCreator ()); -ขณะนี้มีการใช้งานสองครั้งของเครื่องกำเนิดไฟฟ้า เราสามารถเพิ่มเลเยอร์ของรูปลักษณ์ที่นี่และตั้งค่าวิธีการใช้งานเริ่มต้น:
/*** ตอนนี้มีการใช้งานสองครั้งของเครื่องกำเนิดไฟฟ้า มาเพิ่มเลเยอร์ของรูปลักษณ์ที่นี่และตั้งค่าวิธีการใช้งานเริ่มต้น */รูปร่างระดับสาธารณะ {ผู้สร้าง shapecreator สุดท้ายคงที่ = new LiteralCreator (); รูปร่างคงที่สาธารณะแบบสุ่ม () {return creator.randomshape (); } รูปร่างคงที่สาธารณะ [] creatiarray (ขนาด int) {return creator.createArray (ขนาด); } arrayList สาธารณะคงที่ <Mape> arrayList (ขนาด int) {return creator.arrayList (ขนาด); - 3.4. ความเท่าเทียมกันของอินสแตนซ์และคลาส:
ผลลัพธ์ที่สร้างขึ้นโดย instanceof และ isinstance () นั้นเหมือนกันการรักษาแนวคิดของประเภทและพิจารณาว่าคลาสหรือคลาสที่ได้รับของคลาสนี้
Equals () เหมือนกับ == และการใช้วัตถุคลาสที่ใช้งานได้จริงนี้ไม่ได้รับการพิจารณาการสืบทอด
System.out.println (วงกลมใหม่ () อินสแตนซ์ของวงกลม); // truesystem.out.println (shape.class.isinstance (วงกลมใหม่ ())); // truesystem.out.println ((วงกลมใหม่ ()). getClass () == circle.class); // truesystem.out.println ((วงกลมใหม่ (). getclass ()). เท่ากับ (shape.class)); // เท็จ