Generics ใน Java ถูกนำไปใช้โดยการลบประเภท JLS บอกว่าแรงบันดาลใจคือความเข้ากันได้ย้อนหลัง ที่ไหนในทางกลับกัน C # generics จะ reifiable
ในทางทฤษฎีอะไรคือข้อดีและข้อเสียโดยมี Generics เป็น "ลบ" หรือ "reifiable"?
Java หายไปหรือเปล่า
Generics ใน Java ถูกนำไปใช้โดยการลบประเภท JLS บอกว่าแรงบันดาลใจคือความเข้ากันได้ย้อนหลัง ที่ไหนในทางกลับกัน C # generics จะ reifiable
ในทางทฤษฎีอะไรคือข้อดีและข้อเสียโดยมี Generics เป็น "ลบ" หรือ "reifiable"?
Java หายไปหรือเปล่า
คำตอบ:
แรงจูงใจ (ความเข้ากันได้ย้อนหลัง) เป็นทั้งข้อดีและข้อเสีย มันเป็นข้อเสียเพราะเราทุกคนต้องการที่จะมีประเภท reifiable แต่ราคาที่จ่ายสูง พิจารณาตัวเลือกการออกแบบใน C # พวกเขามีประเภทที่พิสูจน์ได้ แต่ตอนนี้พวกเขามี API ที่ซ้ำกัน ลองจินตนาการถึง Java API ที่เรามี API ที่ซ้ำกันสำหรับทุกคลาสที่กำหนดพารามิเตอร์ ทีนี้ลองนึกภาพตัวเองในการย้ายโค้ดหลายพันบรรทัดจากคลาสเก่าไปสู่คลาสทั่วไปใหม่ ตอนนี้ใครจะไม่พิจารณาข้อเสีย API ที่ซ้ำกัน แต่เดี๋ยวก่อนพวกเขามีประเภทที่พิสูจน์ได้!
ดังนั้นแรงจูงใจที่สำคัญคือ "วิวัฒนาการไม่ใช่การปฏิวัติ" และมีเหตุผลทุกการตัดสินใจมีการแลกเปลี่ยน
นอกจากข้อเสียอื่น ๆ ที่กล่าวถึงเราสามารถเพิ่มความจริงที่ว่าการลบประเภทอาจเป็นเรื่องยากที่จะรวบรวมเวลาเนื่องจากไม่เห็นชัดเจนว่าบางประเภทจะถูกลบออกและสิ่งนี้นำไปสู่ข้อผิดพลาดที่แปลกและหายาก
การมีอยู่ของเมธอดบริดจ์ (คอมไพเลอร์วิธีนี้สร้างโดยวิธี syntactically เพื่อรักษาความเข้ากันได้ของไบนารี) สามารถถูกมองว่าเป็นข้อเสีย และสิ่งเหล่านี้สามารถเป็นหนึ่งในสาเหตุของข้อผิดพลาดที่ฉันกล่าวถึงในย่อหน้าก่อนหน้า
ข้อเสียที่สำคัญมาจากความจริงที่ชัดเจนอยู่แล้วว่ามีชั้นเดียวและไม่หลายชั้นสำหรับประเภททั่วไป อีกตัวอย่างหนึ่งพิจารณาว่าการโอเวอร์โหลดวิธีที่มีคลาสทั่วไปเดียวกันล้มเหลวใน Java:
public void doSomething(List<One>);
public void doSomething(List<Two>);
บางสิ่งบางอย่างที่อาจถูกมองว่าเป็นข้อเสียของประเภท reifiable (อย่างน้อยใน C #) เป็นความจริงที่ว่าพวกเขาทำให้เกิดรหัสระเบิด ยกตัวอย่างเช่นList<int>เป็นหนึ่งในชั้นเรียนและList<double>เป็นอีกหนึ่งที่แตกต่างกันโดยสิ้นเชิงมันเป็นและList<string> List<MyType>ดังนั้นคลาสจะต้องถูกกำหนดที่รันไทม์ทำให้เกิดการระเบิดของคลาสและการใช้ทรัพยากรที่มีค่าในขณะที่กำลังถูกสร้างขึ้น
เกี่ยวกับความจริงที่ว่ามันเป็นไปไม่ได้ที่จะนิยาม a new T()ใน Java ที่กล่าวถึงในคำตอบอื่นมันเป็นเรื่องที่น่าสนใจที่จะพิจารณาว่านี่ไม่ใช่แค่เรื่องของการลบประเภท นอกจากนี้ยังต้องการการมีอยู่ของตัวสร้างเริ่มต้นนั่นคือเหตุผลที่ C # ต้องการ "ข้อ จำกัด ใหม่" สำหรับสิ่งนี้ (ดูว่าทำไม T ใหม่ () เป็นไปไม่ได้ใน Javaโดย Alex Buckley)
ข้อเสียของการลบประเภทคือคุณไม่ทราบว่าเป็นประเภททั่วไป นี่หมายความว่าคุณไม่สามารถใช้การสะท้อนกับพวกเขาและคุณไม่สามารถสร้างอินสแตนซ์ได้ที่รันไทม์
คุณไม่สามารถทำสิ่งนี้ใน Java:
public class MyClass<T> {
private T t;
//more methods
public void myMethod() {
//more code
if (someCondition) {
t = new T();//illegal
} else {
T[] array = new T[];//illegal
}
}
}
มีวิธีแก้ปัญหาสำหรับสิ่งนี้ แต่ต้องการรหัสเพิ่มเติม ข้อได้เปรียบดังที่คุณกล่าวถึงคือความเข้ากันได้แบบย้อนหลัง
ข้อดีอีกประการของการลบข้อมูลทั่วไปคือภาษาต่าง ๆ ที่รวบรวมกับ JVM ใช้กลยุทธ์ที่แตกต่างกันสำหรับข้อมูลทั่วไปเช่นไซต์คำจำกัดความของ Scala เทียบกับความแปรปรวนร่วมของเว็บไซต์ใช้งาน Java นอกจากนี้ยาชื่อสามัญที่สูงขึ้นของ Scala ก็ยากที่จะสนับสนุนประเภท reified ของ. Net เนื่องจาก Scala บน. net เพิกเฉยต่อรูปแบบการทำให้เข้ากันไม่ได้ของ C # หากเรามีข้อมูลทั่วไปของ JVM ใหม่เป็นไปได้ว่ายาชื่อสามัญเหล่านี้จะไม่เหมาะกับคุณสมบัติที่เราชอบเกี่ยวกับสกาล่าและเราจะติดอยู่กับสิ่งที่ไม่ดี ข้อความจากบล็อก Ola Bini ของ ,
สิ่งนี้หมายความว่าถ้าคุณต้องการเพิ่ม generics ที่มีการแก้ไขใหม่ให้กับ JVM คุณควรจะแน่ใจว่าการใช้งานนั้นสามารถครอบคลุมทั้งภาษาคงที่ทั้งหมดที่ต้องการทำนวัตกรรมใน generics รุ่นของตนเองและภาษาไดนามิกทั้งหมดที่ต้องการ สร้างการใช้งานที่ดีและสิ่งอำนวยความสะดวกการเชื่อมต่อที่ดีกับห้องสมุด Java เพราะถ้าคุณเพิ่ม reified generics ที่ไม่ตรงตามเกณฑ์เหล่านี้คุณจะยับยั้งนวัตกรรมและทำให้ยากยิ่งขึ้นที่จะใช้ JVM เป็น VM แบบหลายภาษา
โดยส่วนตัวแล้วฉันไม่ได้พิจารณาถึงความจำเป็นในการใช้TypeTagบริบทที่เกี่ยวข้องใน Scala สำหรับวิธีการโอเวอร์โหลดที่ขัดแย้งกันซึ่งเป็นข้อเสียเนื่องจากมันเป็นการย้ายค่าใช้จ่ายและความยืดหยุ่นในการทำให้ซ้ำจากทั่วโลก (ทั้งโปรแกรมและภาษาที่เป็นไปได้ทั้งหมด) ปัญหาที่เป็นเพียงกรณีน้อยบ่อย
Tของคุณจะได้รับเพียงหนึ่งสำเนาของClass<T>รหัสสำหรับทุกTs; บวกสำเนาเพิ่มเติมสำหรับแต่ละประเภทค่าที่Tใช้จริง