ข้อมูลทั่วไปที่เรียกว่า: ช่วยให้คุณสามารถระบุพารามิเตอร์ประเภทเมื่อกำหนดคลาสและอินเทอร์เฟซ พารามิเตอร์ประเภทนี้จะถูกกำหนดเมื่อประกาศตัวแปรและสร้างวัตถุ (นั่นคือการส่งผ่านพารามิเตอร์ประเภทจริง ซึ่งสามารถเรียกว่าอาร์กิวเมนต์ประเภท)
คลาสหรืออินเทอร์เฟซทั่วไป
รหัสคัดลอกไวยากรณ์ "เพชร" เป็นดังนี้:
//คำนิยาม
รายการอินเทอร์เฟซสาธารณะ <E> ขยายคอลเลกชัน <E>
คลาสสาธารณะ HashMap<K,V> ขยาย AbstractMap<K,V> ใช้ Map<K,V>, Cloneable, Serializable
//ใช้
รายการ <สตริง> รายการ = ใหม่ ArrayList();
//หลังจาก Java 7 คุณสามารถละเว้นพารามิเตอร์ type ของวงเล็บมุมด้านหลังได้
รายการ <String> รายการ = ArrayList ใหม่ <>();
รับคลาสย่อยจากคลาสทั่วไป
คัดลอกรหัสรหัสดังต่อไปนี้:
//วิธีที่ 1
แอปคลาสสาธารณะขยาย GenericType<String>
//วิธีที่ 2
แอปคลาสสาธารณะ<T> ขยาย GenericType<T>
//วิธีที่ 3
แอปคลาสสาธารณะขยาย GenericType
ชื่อสามัญหลอก
ไม่มีคลาสทั่วไปที่แท้จริง คลาสทั่วไปมีความโปร่งใสกับเครื่องเสมือน Java JVM ไม่ทราบว่ามีคลาสทั่วไปอยู่ หรืออีกนัยหนึ่ง JVM ประมวลผลคลาสทั่วไปไม่แตกต่างจากคลาสทั่วไป ในวิธีการแบบคงที่ บล็อกการเริ่มต้นแบบคงที่ และตัวแปรแบบคงที่
- วิธีการต่อไปนี้ผิดทั้งหมด รหัสการคัดลอกมีดังนี้:
ข้อมูล T ส่วนตัวแบบคงที่
คงที่{
ทีฉ;
-
โมฆะสาธารณะคง func () {
ชื่อ T = 1;
-
ตัวอย่างต่อไปนี้สามารถตรวจสอบจากด้านข้างว่าไม่มีคลาสทั่วไป โค้ดมีดังนี้:
โมฆะคงที่สาธารณะ main (String [] args) {
รายการ <สตริง> a1 = รายการอาร์เรย์ใหม่ <>();
รายการ<จำนวนเต็ม> a2 = รายการอาร์เรย์ใหม่<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
-
รหัสการคัดลอกผลลัพธ์จะเป็นดังนี้:
จริง
คลาส java.util.ArrayList
คลาส java.util.ArrayList
พิมพ์ไวด์การ์ด
ก่อนอื่น ต้องชัดเจนว่าถ้า Foo เป็นคลาสหลักของ Bar แต่ List<Foo> ไม่ใช่คลาสหลักของ List<Bar> เพื่อแสดงถึงคลาสพาเรนต์ทั่วไปต่างๆ Java จะใช้ "?" เพื่อเป็นตัวแทน ไวด์การ์ดทั่วไป นั่นคือ List<?> แสดงถึงคลาสพาเรนต์ของรายการทั่วไปต่างๆ ด้วยไวด์การ์ดประเภทนี้ List generics ไม่สามารถตั้งค่า (ตั้งค่า) องค์ประกอบได้ แต่สามารถรับได้เฉพาะองค์ประกอบเท่านั้น เนื่องจากโปรแกรมไม่สามารถระบุประเภทในรายการได้ จึงไม่สามารถเพิ่มอ็อบเจ็กต์ได้ แต่วัตถุที่ได้รับจะต้องเป็นประเภทวัตถุ
วิธีการต่อไปนี้จะคอมไพล์โดยมีข้อผิดพลาด:
คัดลอกรหัสรหัสดังต่อไปนี้:
รายการ<?> รายการ = ArrayList ใหม่<>();
list.add(วัตถุใหม่());
แนวคิดบางประการ:
1. ไม่สามารถใช้วัตถุ List<String> เป็นวัตถุ List<Object> ได้ กล่าวคือ: คลาส List<String> ไม่ใช่คลาสย่อยของคลาส List<Object>
2. อาร์เรย์แตกต่างจากข้อมูลทั่วไป: สมมติว่า Foo เป็นประเภทย่อย (คลาสย่อยหรืออินเทอร์เฟซย่อย) ของ Bar ดังนั้น Foo[] ยังคงเป็นประเภทย่อยของ Bar[]; แต่ G<Foo> ไม่ใช่ประเภทย่อย G<Bar>
3. เพื่อเป็นตัวแทนคลาสหลักของรายการทั่วไปต่างๆ เราจำเป็นต้องใช้ประเภทไวด์การ์ดคือเครื่องหมายคำถาม (?) ส่งผ่านเครื่องหมายคำถามเป็นอาร์กิวเมนต์ประเภทไปยังคอลเลกชันรายการ โดยเขียนว่า: List<? > (หมายถึงรายการองค์ประกอบประเภทที่ไม่รู้จัก) เครื่องหมายคำถาม (?) นี้เรียกว่าอักขระไวด์การ์ด และประเภทองค์ประกอบสามารถจับคู่กับประเภทใดก็ได้
ขีดจำกัดบนของไวด์การ์ด
List<? ขยาย SuperType> แสดงถึงคลาสพาเรนต์หรือตัวมันเองของรายการทั่วไป SuperType ทั้งหมด ข้อมูลทั่วไปที่มีขีดจำกัดบนของ wildcard ไม่สามารถตั้งค่าวิธีการได้ แต่จะรับเฉพาะวิธีการเท่านั้น
การตั้งค่าขีดจำกัดสูงสุดของ wildcard สามารถแก้ปัญหาต่อไปนี้ได้ Dog เป็นคลาสย่อยของ Animal และมีเมธอด getSize เพื่อรับจำนวนรายการที่เข้ามา รหัสมีดังนี้
สัตว์ระดับนามธรรม {
โมฆะนามธรรมสาธารณะวิ่ง ();
-
คลาส Dog ขยายสัตว์ {
โมฆะสาธารณะวิ่ง () {
System.out.println("สุนัขวิ่ง");
-
-
แอปคลาสสาธารณะ {
โมฆะสาธารณะคงที่ getSize (รายการ <สัตว์> รายการ) {
System.out.println(list.size());
-
โมฆะสาธารณะคงหลัก (สตริง [] args) {
รายการ <Dog> รายการ = ArrayList ใหม่ <>();
getSize(list); // เกิดข้อผิดพลาดในการคอมไพล์ที่นี่
-
-
สาเหตุของข้อผิดพลาดในการเขียนโปรแกรมที่นี่คือ List<Animal> ไม่ใช่คลาสหลักของ List<Dog> วิธีแก้ปัญหาแรกคือเปลี่ยนพารามิเตอร์อย่างเป็นทางการ List<Animal> ในเมธอด getSize เป็น List<?> แต่ในกรณีนี้ จำเป็นต้องแปลงประเภทแบบบังคับทุกครั้งที่ได้รับอ็อบเจ็กต์ ซึ่งยุ่งยากกว่า การใช้ขีดจำกัดบนของไวด์การ์ดช่วยแก้ปัญหานี้ได้เป็นอย่างดี คุณสามารถเปลี่ยน List<Animal> เป็น List<? ขยาย Animal> และจะไม่มีข้อผิดพลาดในการคอมไพล์ และไม่จำเป็นต้องแปลงประเภท
ขอบเขตล่างสำหรับไวด์การ์ด
รายการ <? super SubType> แสดงถึงขีดจำกัดล่างของรายการทั่วไปของประเภทย่อย ข้อมูลทั่วไปที่มีขีดจำกัดบนของไวด์การ์ดไม่สามารถรับเมธอดได้ แต่จะตั้งค่าเมธอดเท่านั้น
วิธีการทั่วไป
หากคุณกำหนดคลาสและอินเทอร์เฟซโดยไม่ใช้พารามิเตอร์ประเภท แต่ต้องการกำหนดพารามิเตอร์ประเภทด้วยตัวเองเมื่อกำหนดวิธีการ สิ่งนี้ก็เป็นไปได้เช่นกันที่ให้การสนับสนุนสำหรับวิธีการทั่วไป ลายเซ็นวิธีการของวิธีการทั่วไปมีการประกาศพารามิเตอร์ประเภทมากกว่าการประกาศพารามิเตอร์ประเภทจะอยู่ในวงเล็บมุม ตัวดัดแปลงและประเภทค่าส่งคืนของวิธีการ รูปแบบไวยากรณ์จะเป็นดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
ตัวแก้ไขชื่อวิธีประเภทค่าส่งคืน (รายการประเภท) {
//เนื้อความวิธีการ
-
วิธีการทั่วไปอนุญาตให้ใช้พารามิเตอร์ประเภทเพื่อแสดงการพึ่งพาประเภทระหว่างพารามิเตอร์ตั้งแต่หนึ่งพารามิเตอร์ขึ้นไปของวิธีการ หรือระหว่างค่าส่งคืนของวิธีการและพารามิเตอร์ หากไม่มีการอ้างอิงประเภทดังกล่าว ไม่ควรใช้วิธีทั่วไป วิธีการคัดลอกคอลเลกชันใช้วิธีการทั่วไป:
คัดลอกรหัสรหัสดังต่อไปนี้:
สาธารณะคงคัดลอกโมฆะ <T> (รายการ <? super T> ปลายทาง, รายการ <? ขยาย T> src) { ... }
วิธีการนี้กำหนดให้ประเภท src ต้องเป็นคลาสย่อยของประเภทปลายทางหรือตัวมันเอง
ลบและแปลง
ในโค้ดทั่วไปที่เข้มงวด คลาสที่มีการประกาศทั่วไปควรมีพารามิเตอร์ประเภทเสมอ อย่างไรก็ตาม เพื่อให้สอดคล้องกับโค้ด Java เก่า จึงอนุญาตให้ใช้คลาสที่มีการประกาศทั่วไปโดยไม่ต้องระบุพารามิเตอร์ประเภท หากไม่มีการระบุพารามิเตอร์ประเภทสำหรับคลาสทั่วไปนี้ พารามิเตอร์ประเภทจะเรียกว่าประเภทดิบและจะมีค่าเริ่มต้นเป็นประเภทขีดจำกัดบนแรกที่ระบุเมื่อมีการประกาศพารามิเตอร์
เมื่อออบเจ็กต์ที่มีข้อมูลทั่วไปถูกกำหนดให้กับตัวแปรอื่นที่ไม่มีข้อมูลทั่วไป ข้อมูลประเภททั้งหมดระหว่างวงเล็บมุมจะถูกโยนทิ้งไป ตัวอย่างเช่น หากประเภท List<String> ถูกแปลงเป็นรายการ การตรวจสอบประเภทขององค์ประกอบคอลเลกชันของรายการจะกลายเป็นขีดจำกัดบนของตัวแปรประเภท (นั่นคือ อ็อบเจ็กต์) สถานการณ์นี้เรียกว่าการลบออก
รหัสการคัดลอกตัวอย่างจะเป็นดังนี้:
คลาส Apple<T ขยายหมายเลข>
-
ขนาดที;
สาธารณะแอปเปิ้ล()
-
-
แอปเปิ้ลสาธารณะ(ขนาดT)
-
this.size = ขนาด;
-
โมฆะสาธารณะ setSize(ขนาด T)
-
this.size = ขนาด;
-
สาธารณะ T getSize()
-
ส่งคืน this.size;
-
-
ErasureTest ในชั้นเรียนสาธารณะ
-
โมฆะสาธารณะคง main (String [] args)
-
แอปเปิ้ล<จำนวนเต็ม> a = แอปเปิ้ลใหม่<>(6); // ①
// วิธีการ getSize ของส่งคืนวัตถุจำนวนเต็ม
จำนวนเต็มเป็น = a.getSize();
// กำหนดวัตถุให้กับตัวแปร Apple โดยสูญเสียข้อมูลประเภทในวงเล็บมุม
แอปเปิ้ล ข = ก; // ②
// b รู้เพียงว่าประเภทขนาดคือ Number
ตัวเลข size1 = b.getSize();
//รหัสต่อไปนี้ทำให้เกิดข้อผิดพลาดในการคอมไพล์
ขนาดจำนวนเต็ม2 = b.getSize(); // 3
-
-