“สวัสดี อามีโก้!”

“สวัสดี เอลลี่!”

“วันนี้ ผมกับฤๅษีจะมาเล่าเรื่องยาชื่อสามัญให้คุณฟัง”

“เดี๋ยวก่อน ฉันคิดว่าฉันรู้เกือบทุกอย่างแล้ว”

"เกือบทุกอย่าง แต่ไม่ใช่ทั้งหมด"

“จริงเหรอ โอเค ฉันพร้อมฟัง”

"งั้นเรามาเริ่มกันเลย"

"ใน 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 เสมอ"

“ก็ฉลาดดีนี่”