“สวัสดี อามีโก้!”
“สวัสดี เอลลี่!”
“วันนี้ ผมกับฤๅษีจะมาเล่าเรื่องยาชื่อสามัญให้คุณฟัง”
“เดี๋ยวก่อน ฉันคิดว่าฉันรู้เกือบทุกอย่างแล้ว”
"เกือบทุกอย่าง แต่ไม่ใช่ทั้งหมด"
“จริงเหรอ โอเค ฉันพร้อมฟัง”
"งั้นเรามาเริ่มกันเลย"
"ใน Java ชื่อสามัญคือคลาสที่มีพารามิเตอร์ประเภท"
"เหตุใดจึงมีการคิดค้นชื่อสามัญ ดูความคิดเห็นในโค้ด:"
ArrayList stringList = new ArrayList();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // Add a number to the list
for(Object o: stringList)
{
String s = (String) o; // There will be an exception here when we get to the integer
}
วิธีแก้ปัญหาโดยใช้ Generics:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // There will be a compilation error here
for(Object o: stringList)
{
String s = (String) o;
}
"โค้ดนี้ไม่สามารถคอมไพล์ได้ และข้อผิดพลาดที่เกิดจากการเพิ่มประเภทข้อมูลผิดจะถูกตรวจพบระหว่างการคอมไพล์"
“ใช่ ฉันรู้เรื่องนี้แล้ว”
"โอเค ดี การทำซ้ำคือแม่ของการเรียนรู้"
"แต่ผู้สร้างของ Java ค่อนข้างขี้เกียจเล็กน้อยเมื่อพวกเขาสร้างชื่อสามัญ แทนที่จะสร้างประเภทที่สมบูรณ์ด้วยพารามิเตอร์ พวกเขาลดประสิทธิภาพลงอย่างลื่นไหล ในความเป็นจริง พวกเขาไม่ได้เพิ่มข้อมูลใดๆ เกี่ยวกับพารามิเตอร์ประเภทให้กับชื่อสามัญ แต่ทั้งหมด เวทมนตร์เกิดขึ้นระหว่างการรวบรวม"
List<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("abc");
strings.add( 1); // Compilation error
for(String s: strings)
{
System.out.println(s);
}
List strings = new ArrayList();
strings.add((String)"abc");
strings.add((String)"abc");
strings.add((String) 1); // Compilation error
for(String s: strings)
{
System.out.println(s);
}
"เนียนจังเลย"
"ใช่ แต่วิธีนี้มีผลข้างเคียง ไม่มีข้อมูลเกี่ยวกับพารามิเตอร์ประเภทถูกเก็บไว้ในคลาสทั่วไป วิธีนี้ต่อมากลายเป็นที่รู้จักในชื่อtype Eresure "
"อีกนัยหนึ่ง ถ้าคุณมีคลาสของคุณเองที่มีพารามิเตอร์ประเภท คุณจะไม่สามารถใช้ข้อมูลเกี่ยวกับคลาสเหล่านั้นภายในคลาสได้"
class Zoo<T>
{
ArrayList<T> pets = new ArrayList<T>();
public T createAnimal()
{
T animal = new T();
pets.add(animal)
return animal;
}
}
class Zoo
{
ArrayList pets = new ArrayList();
public Object createAnimal()
{
Object animal = new ???();
pets.add(animal)
return animal;
}
}
"ระหว่างการคอมไพล์ ประเภทพารามิเตอร์ทั้งหมดจะถูกแทนที่ด้วย Object และภายในคลาสจะไม่มีข้อมูลเกี่ยวกับประเภทที่ส่งผ่านไปยังคลาสนั้น"
“ใช่ ฉันเห็นด้วย นั่นไม่ใช่สิ่งที่ดีที่สุด”
“มันไม่ได้น่ากลัวขนาดนั้น ฉันจะบอกวิธีแก้ไขปัญหานี้ทีหลัง”
แต่มีมากขึ้น Java ให้คุณระบุประเภทพาเรนต์สำหรับพารามิเตอร์ประเภท คำหลักขยายใช้สำหรับสิ่งนี้ ตัวอย่างเช่น:
class Zoo<T extends Cat>
{
T cat;
T getCat()
{
return cat;
}
void setCat (T cat)
{
this.cat = cat;
}
String getCatName()
{
return this.cat.getName();
}
}
class Zoo
{
Cat cat;
Cat getCat()
{
return cat;
}
void setCat(Cat cat)
{
this.cat = cat;
}
String getCatName()
{
return this.cat.getName();
}
}
"หมายเหตุข้อเท็จจริงสองประการ:"
"ประการแรก คุณไม่สามารถส่งผ่านประเภทใด ๆ เป็นพารามิเตอร์ได้ - คุณสามารถส่งผ่าน Cat หรือคลาสที่สืบทอด Cat ได้เท่านั้น"
"ประการที่สอง ภายในคลาส Zoo ตัวแปรประเภท T สามารถเรียกเมธอดของคลาส Cat ได้แล้ว คอลัมน์ทางขวาจะอธิบายว่าทำไม (เพราะ Cat จะถูกแทนที่ทุกที่ที่มี T)"
"ใช่ ถ้าเราบอกว่า Cat หรือคลาสย่อยของ Cat ถูกส่งผ่านเป็นอาร์กิวเมนต์ประเภท เราก็แน่ใจว่าประเภท T จะมีเมธอดของคลาส Cat เสมอ"
“ก็ฉลาดดีนี่”
GO TO FULL VERSION