เรื่องสั้น
จำกัด องค์ประกอบในการรวบรวมเป็นประเภทเฉพาะ
คำว่า
หมายเหตุเล็กน้อย:
ประเภทพารามิเตอร์และประเภทดั้งเดิมนั้นเข้ากันได้กับกันและกัน
ArrayList Collection1 = new ArrayList <Integer> (); // pass, ไม่มี warningArrayList <จำนวนเต็ม> collection2 = new ArrayList (); // ผ่านมีคำเตือน
ประเภทพารามิเตอร์ไม่พิจารณาความสัมพันธ์ในการสืบทอดของพารามิเตอร์ประเภท
ArrayList <String> Collection3 = new ArrayList <Ojrop> (); // การรวบรวมไม่ผ่าน ArrayList <Ojrop> Collection4 = new ArrayList <String> (); // การรวบรวมไม่ผ่าน
แต่
ArrayList Collection5 = New ArrayList <Integer> (); ArrayList <String> Collection6 = Collection5; // รวบรวมโดย
- ไพ่
- หมายถึงทุกประเภท ใช้ "?" อักขระไวด์การ์ดเพื่ออ้างถึงประเภทพารามิเตอร์ต่างๆ มันสามารถเรียกวิธีการที่ไม่เกี่ยวข้องกับการกำหนดค่าพารามิเตอร์ (เช่นขนาด () วิธีการ) และไม่สามารถเรียกใช้วิธีการที่เกี่ยวข้องกับการกำหนดพารามิเตอร์ (เช่นวิธีการเพิ่ม ())
ส่วนขยายของไวด์การ์ด
มีคุณสมบัติขอบเขตบนของตัวละครไวลด์การ์ด
arraylist <? ขยายหมายเลข> Collection1 = arrayList ใหม่ <integer> (); // รวบรวมโดย arraylist <? ขยายหมายเลข> collection2 = arrayList ใหม่ <String> (); // รวบรวมโดยไม่
มีคุณสมบัติขอบเขตล่างของอักขระไวด์การ์ด
arraylist <? Super Integer> Collection3 = new ArrayList <Number> (); // รวบรวมโดย ArrayList <? Super Integer> Collection4 = arrayList ใหม่ <String> (); // รวบรวมโดยไม่
วิธีการทั่วไปที่กำหนดเอง
ฟังก์ชันเทมเพลต C ++
เทมเพลต <คลาส t> t เพิ่ม (t x, t y) {return (t) (x+y);}Java Generics นั้นถูกนำมาใช้โดยทั่วไปในคอมไพเลอร์โดยคอมไพเลอร์ที่ใช้เพื่อทำการตรวจสอบประเภทและการตัดสินประเภทจากนั้นสร้างไบต์ที่ไม่ใช่ Generic ทั่วไป เทคนิคการใช้งานนี้คือ "ลบ"
อินสแตนซ์ "ลบ"
มีการจัดเตรียมทั่วไปให้กับคอมไพเลอร์ Javac เพื่อกำหนดประเภทอินพุตของคอลเลกชัน เมื่อคอมไพเลอร์รวบรวมคอลเลกชันที่มีคำอธิบายประเภทข้อมูล "ประเภท" จะถูกลบออก
คลาสสาธารณะ generictest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ใหม่ generictest (). testtype (); } โมฆะสาธารณะ testType () {arrayList <integer> คอลเลกชัน 1 = arrayList ใหม่ <Integer> (); ArrayList <String> Collection2 = new ArrayList <String> (); System.out.println (Collection1.getClass () == Collection2.getClass ()); // ประเภทคลาสของทั้งสองนั้นเหมือนกันนั่นคือ bytecode เป็น system.out.println (collection2.getClass (). getName ()); // คลาสคือ java.util.arraylist และไม่มีข้อมูลพารามิเตอร์ประเภทจริง}}}เอาท์พุท
จริง
java.util.arraylist
ใช้การสะท้อนกลับเพื่อข้ามคอมไพเลอร์และเพิ่มข้อมูลประเภทอื่น ๆ ลงในคอลเลกชันทั่วไป
สามารถใช้เฉพาะประเภทอ้างอิงเป็นพารามิเตอร์จริงสำหรับวิธีการทั่วไป:
คลาสสาธารณะ generictest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {swap (สตริงใหม่ [] {"111", "222"}, 0,1); // รวบรวมโดย // swap (int ใหม่ [] {1,2}, 0,1); // คอมไพล์โดยไม่รวบรวมเพราะ int ไม่ใช่การแลกเปลี่ยนประเภทการอ้างอิง (จำนวนเต็มใหม่ [] {1,2}, 0,1); // รวบรวมโดย}/*เปลี่ยนองค์ประกอบ i-th และ j ของอาร์เรย์ a*/สาธารณะคงที่ <t> swap (t [] a, int i, int J) a [i] = a [j]; A [j] = อุณหภูมิ; -แต่โปรดทราบว่าบางครั้งประเภทพื้นฐานสามารถใช้เป็นพารามิเตอร์จริงได้เนื่องจากมีการบรรจุอัตโนมัติและการยกเลิกการบ็อกซ์ ตัวอย่าง (รวบรวมและผ่าน):
คลาสสาธารณะ generictest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ใหม่ generictest (). testtype (); int a = biggerone (3,5); // int และ double รับการแลกเปลี่ยนเป็นหมายเลขหมายเลข b = biggerone (3,5.5); // string และ int รับการแลกเปลี่ยนเป็นวัตถุวัตถุ c = biggerone ("1", 2); } // return y จาก x, y สาธารณะคงที่ <t> t biggerone (t x, t y) {return y; -ในเวลาเดียวกันตัวอย่างนี้ยังแสดงให้เห็นว่าเมื่อพารามิเตอร์จริงไม่สอดคล้องกัน T ใช้เวลาสี่แยกนั่นคือคลาสหลักทั่วไป นอกจากนี้หากคุณใช้หมายเลข b = biggerone (3,5.5); ถึงสตริง c = biggerone (3,5.5); จากนั้นรายงานข้อผิดพลาดในการรวบรวม:
ข้อผิดพลาด: (17, 29) Java: ประเภทที่เข้ากันไม่ได้: ประเภทที่อนุมานไม่ตรงตามขีด จำกัด สูงสุด: java.lang.number & java.lang.comparable <? ขยาย java.lang.number & java.lang.comparable <? >>
ขีด จำกัด บน: java.lang.string, java.lang.Object
แต่มีสิ่งหนึ่งที่ฉันไม่เข้าใจ ฉันดีบั๊กทีละขั้นตอนในความคิดและพบว่าผลลัพธ์มีดังนี้: การดีบักการดีบักทั่วไปหน้าจอ -1 ฉันไม่รู้ว่าทำไม B ถึงเป็นสองเท่า (แต่มันจะรวบรวมและรายงานข้อผิดพลาดเมื่อได้รับค่าคืนค่าในสอง b) ฉันไม่รู้ว่ามันเกี่ยวข้องกับ IDE หรือไม่ IDE แสดงประเภทของวัตถุนี้ที่แม่นยำที่สุดเมื่อทำการดีบักหรือไม่?
พิมพ์การอนุมานของประเภทพารามิเตอร์
กระบวนการที่คอมไพเลอร์ตัดสินพารามิเตอร์ประเภทจริงของวิธีการทั่วไปเรียกว่าการอนุมานประเภท
เมื่อตัวแปรประเภทหนึ่งถูกนำไปใช้เพียงหนึ่งในพารามิเตอร์และค่าส่งคืนทั้งหมดในรายการพารามิเตอร์ทั้งหมดจะถูกกำหนดตามประเภทแอปพลิเคชันจริงในเวลานั้นเมื่อมีการเรียกวิธีการ นั่นคือประเภทของพารามิเตอร์ทั่วไปจะถูกกำหนดโดยตรงตามประเภทพารามิเตอร์หรือค่าส่งคืนที่ส่งผ่านเมื่อมีการเรียกวิธีการ ตัวอย่างเช่น:
swap (สตริงใหม่ [3], 1,2) -> คงที่ <e> การแลกเปลี่ยนโมฆะ (e [] a, int i, int j)
เมื่อตัวแปรประเภทถูกนำไปใช้ในหลาย ๆ สถานที่ในพารามิเตอร์ทั้งหมดและค่าส่งคืนของรายการพารามิเตอร์ทั้งหมดหากแอปพลิเคชันประเภทจริงจำนวนมากสอดคล้องกับประเภทเดียวกันเมื่อเรียกวิธีการประเภทของพารามิเตอร์ทั่วไปคือประเภทนั้น ตัวอย่างเช่น:
เพิ่ม (3,5) -> คงที่ <t> t เพิ่ม (t a, t b)
เมื่อตัวแปรประเภทหนึ่งถูกนำไปใช้ในหลาย ๆ สถานที่ในพารามิเตอร์ทั้งหมดและค่าส่งคืนของรายการพารามิเตอร์ทั้งหมดหากแอปพลิเคชันประเภทจริงในสถานที่หลายแห่งสอดคล้องกับประเภทที่แตกต่างกันเมื่อเรียกใช้วิธีการและไม่มีค่าส่งคืนประเภทการแยกสูงสุดระหว่างพารามิเตอร์หลายตัว ตัวอย่างเช่น:
เติม (จำนวนเต็มใหม่ [3], 3.5) -> คงที่ <t> โมฆะเติม (t a [], t v)
ประเภทที่สอดคล้องกันจริงของตัวอย่างนี้คือตัวเลขรวบรวมและเรียกใช้ปัญหา
เมื่อตัวแปรประเภทถูกนำไปใช้ในหลายสถานที่ในพารามิเตอร์ทั้งหมดและค่าส่งคืนของรายการพารามิเตอร์ทั้งหมดหากแอปพลิเคชันประเภทจริงในหลาย ๆ สถานที่สอดคล้องกับประเภทที่แตกต่างกันเมื่อเรียกวิธีการและมีค่าส่งคืนประเภทของค่าส่งคืนจะได้รับลำดับความสำคัญเช่น:
int x = เพิ่ม (3,3.5) -> คงที่ <t> t เพิ่ม (t a, t b)
ตัวอย่างข้อผิดพลาดที่รวบรวมไว้ข้างต้นและประเภท X ถูกเปลี่ยนเป็น Float ยังรายงานข้อผิดพลาดและการเปลี่ยนตัวเลขจะสำเร็จ
ตัวอย่างของการอนุมานประเภทของประเภทพารามิเตอร์คือสกรรมกริยา:
คัดลอก (ใหม่จำนวนเต็ม [5], สตริงใหม่ [5]) -> คงที่ <t> void copy (t [] a, t [] b)
ตัวอย่างนี้ทำให้ประเภทพารามิเตอร์จริงเป็นวัตถุและรวบรวมผ่าน
คัดลอก (arraylist ใหม่ <String>, จำนวนเต็มใหม่ [5]) -> คงที่ <t> void copy (คอลเลกชัน <t> a, t [] b)
ตัวอย่างนี้จะกำหนดตัวแปรประเภทโดยตรงเป็นประเภทสตริงตามอินสแตนซ์ของคลาส ArrayList Parameterized และรายงานข้อผิดพลาดในการรวบรวม
คลาสทั่วไปที่กำหนดเอง
ตัวอย่าง
คลาสสาธารณะ GenericDao <T> {โมฆะสาธารณะเพิ่ม (t x) {} สาธารณะ t findById (int id) {return null; } โมฆะสาธารณะลบ (t obj) {} โมฆะสาธารณะลบ (ID int) {} การอัปเดตโมฆะสาธารณะ (t obj) {} สาธารณะ t findByUserName (ชื่อสตริง) {return null; } สาธารณะ <t> set <t> findByConditions (สตริงที่) {return null; -หมายเหตุ: เมื่อตัวแปรถูกประกาศว่าเป็นทั่วไปมันสามารถเรียกได้โดยตัวแปรอินสแตนซ์และวิธีการ (และประเภทที่ฝังอยู่) แต่ไม่ใช่โดยตัวแปรคงที่และวิธีการคงที่ เนื่องจากสมาชิกแบบคงที่ถูกใช้ร่วมกันโดยคลาสพารามิเตอร์สมาชิกคงที่ไม่ควรมีพารามิเตอร์ประเภทระดับชั้นเรียน
การเปรียบเทียบวิธีการทั่วไปและคลาสทั่วไป
ตัวอย่าง:
คลาสสาธารณะ A <t> () {// วิธีการสมาชิกของคลาสทั่วไป, t ถูก จำกัด โดย t หลังจาก public t memberfunc () {return null; } // วิธีการทั่วไปที่นี่ t และ t แตกต่างจาก t ของคลาส A สาธารณะคงที่ <t> t genericfunc (t a) {return null; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// รวบรวมโดยไม่ต้องผ่าน // จำนวนเต็ม i = a <string> (). findByUserName ("s"); // รวบรวมโดย set <integer> set = a <string> (). findByConditions ("s"); -ที่นี่จำนวนเต็ม i = a <string> (). findByUserName ("s"); จะรวบรวมและรายงานข้อผิดพลาด:
ข้อผิดพลาด: (35, 61) Java: ประเภทที่เข้ากันไม่ได้: java.lang.string ไม่สามารถแปลงเป็น java.lang.integer
จากตัวอย่างนี้จะเห็นได้ว่า t ของวิธีทั่วไปและ t ของคลาส A นั้นแตกต่างกัน
ทั่วไปและภาพสะท้อน
รับพารามิเตอร์ประเภทจริงของทั่วไปผ่านการสะท้อนกลับ
ใช้ตัวแปรทั่วไปเป็นพารามิเตอร์ของวิธีการและใช้วิธี getGenericParameterTypes ของคลาสเมธอดเพื่อให้ได้ตัวอย่างพารามิเตอร์ประเภทจริงของทั่วไป:
คลาสสาธารณะ generictest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) โยนข้อยกเว้น {getParamtype (); } /*ใช้การสะท้อนกลับเพื่อรับพารามิเตอร์ประเภทพารามิเตอร์ที่แท้จริงของพารามิเตอร์วิธี* / โมฆะคงที่สาธารณะ getParamtype () พ่น nosuchmethodexception {วิธีการ = generictest.class.getMethod ("applimap", map.class); // รับประเภทของพารามิเตอร์ทั่วไปของประเภทวิธี [] types = method.getGenericParameterTypes (); System.out.println (ประเภท [0]); // parameterized ประเภท parameterizedType ptype = (parameterizedType) ประเภท [0]; // ประเภท primitive system.out.println (ptype.getrawtype ()); // พารามิเตอร์ประเภทจริง System.out.println (ptype.getActualtyPearguments () [0]); System.out.println (ptype.getactualtypearguments () [1]); } /* วิธีการสำหรับการทดสอบประเภทพารามิเตอร์* / โมฆะคงที่สาธารณะใช้งาน Mapp (แผนที่ <จำนวนเต็ม, สตริง> แผนที่) {}}ผลลัพธ์ผลลัพธ์:
java.util.map <java.lang.integer, java.lang.string> อินเตอร์เฟส java.util.mapclass java.lang.integerclass java.lang.string