ก่อนหน้านี้เราใช้คลาสเพื่อสร้างประเภทใหม่ และใช้การสืบทอดเพื่ออำนวยความสะดวกในกระบวนการสร้างคลาสของเรา ในการบรรยายนี้ ผมจะเจาะลึกเกี่ยวกับประเภทต่างๆ และแนะนำแนวคิดเรื่องความหลากหลาย
การตรวจสอบประเภท
ตัวแปรและการอ้างอิงใดๆ ใน Java สามารถใช้ได้หลังจากผ่านการประกาศประเภทแล้วเท่านั้น เราได้เห็นมาก่อนแล้วว่าข้อมูลอ็อบเจ็กต์ ข้อมูลคลาส พารามิเตอร์ของเมธอด ค่าส่งคืนของเมธอด และตัวแปรอัตโนมัติภายในเมธอด ล้วนจำเป็นต้องประกาศประเภทของมัน Java เป็นภาษาที่พิมพ์อย่างรุนแรงซึ่งจะตรวจสอบประเภท หากเราใช้ผิดประเภทก็จะทำให้เกิดข้อผิดพลาด
ประเภทไม่ตรงกัน ความน่ารักไม่ถูกต้อง
ตัวอย่างเช่น ในคลาส Test ด้านล่าง เรากำหนดอ็อบเจ็กต์คลาส Cup ให้กับการอ้างอิงคลาส aPerson:
การทดสอบคลาสสาธารณะ { public static void main (String [] args) { Human aPerson; aPerson = new Cup (); }} คลาส Human { /** * Constructor */ public Human (int h) { this.height = h; } /** * accessor */ public int getHeight() { return this.height; } /** * mutator */ public void growHeight(int h) { this.height = this.height + h; int height;} class Cup { โมฆะสาธารณะ addWater (int w) { this.water = this.water + w; } โมฆะสาธารณะ drinkWater (int w) { this.water = this.water - w; } น้ำ int ส่วนตัว = 0 ;}
javac จะกลับมา:
พบ: Cuprequired: Human aPerson = new Cup(); ^1 error
การแปลงประเภทพื้นฐาน
Java สามารถทำการแปลงประเภทกับตัวแปรประเภทพื้นฐานได้ ประเภทพื้นฐานที่แตกต่างกันมีความยาวและช่วงการจัดเก็บที่แตกต่างกัน หากเราแปลงจากประเภทที่มีความแม่นยำสูงไปเป็นประเภทที่มีความแม่นยำต่ำ เช่น การแปลงจาก float เป็น int เราอาจสูญเสียข้อมูล การแปลงเช่นนี้เรียกว่าการแปลงแบบแคบลง ในกรณีนี้ เราจำเป็นต้องประกาศการแปลงประเภทอย่างชัดเจน เช่น:
การทดสอบคลาสสาธารณะ { public static void main (String [] args) { int a; a = (int) 1.23; // การจำกัดการแปลง System.out.println (a);
หากเราแปลงจากประเภทที่มีความแม่นยำต่ำไปเป็นประเภทที่มีความแม่นยำสูง ก็ไม่ต้องกังวลเกี่ยวกับการสูญเสียข้อมูล การเปลี่ยนแปลงดังกล่าวเรียกว่าการเปลี่ยนใจกว้าง เราไม่จำเป็นต้องแปลงประเภทอย่างชัดเจน Java สามารถทำได้โดยอัตโนมัติ:
การทดสอบคลาสสาธารณะ { public static void main (String [] args) { int a = 3; double b; b = a; // ขยับขยาย System.out.println (a);
การแปลงประเภทพื้นฐาน
อัปลักษณ์และความหลากหลาย
ใน Java การอ้างอิงสามารถเป็นแบบพิมพ์ได้ แต่ก็มีข้อจำกัด
เราสามารถแปลงการอ้างอิงคลาสที่ได้รับไปเป็นการอ้างอิงคลาสพื้นฐาน ซึ่งเรียกว่าการแปลงแบบ upcast หรือแบบผ่อนคลาย คลาส BrokenCup ต่อไปนี้สืบทอดมาจากคลาส Cup และแทนที่เมธอด addWater() และ drinkWater() ดั้งเดิมในคลาส Cup:
การทดสอบคลาสสาธารณะ { สาธารณะคงเป็นโมฆะ main (String [] args) { Cup aCup; BrokenCup aBrokenCup = new BrokenCup (); aCup = aBrokenCup; // upcast aCup.addWater (10); เป็นโมฆะ addWater (int w) { this.water = this.water + w; } สาธารณะ โมฆะ drinkWater (int w) { this.water = this.water - w; } น้ำ int ส่วนตัว = 0;} คลาส BrokenCup ขยายถ้วย { โมฆะสาธารณะ addWater (int w) { System.out.println ("อึ, ถ้วยแตก"); } โมฆะสาธารณะ drinkWater (int w) { System.out. println("om...num..., ไม่มีน้ำอยู่ข้างใน" }}
ผลการรันโปรแกรม:
อึถ้วยแตก
ดังที่คุณเห็นข้างต้น หากไม่มีคำแนะนำที่ชัดเจน เราจะกำหนดการอ้างอิงคลาสที่ได้รับ aBrokenCup ให้กับ aCup การอ้างอิงคลาสพื้นฐาน การแปลงประเภทจะดำเนินการโดยอัตโนมัติโดย Java
จากนั้นเราเรียกเมธอด addWater() ของ aCup (ซึ่งเราประกาศว่าเป็นประเภท Cup) แม้ว่า aCup จะอ้างอิงถึงประเภท Cup แต่จริงๆ แล้วเรียกเมธอด addWater() ของ BrokenCup! กล่าวอีกนัยหนึ่ง แม้ว่าเราจะคลายประเภทการอ้างอิงไปยังคลาสพื้นฐานผ่าน upcast แต่ Java ยังสามารถระบุประเภทของอ็อบเจ็กต์ได้อย่างถูกต้องและเรียกใช้เมธอดที่ถูกต้อง Java สามารถระบุประเภทที่แท้จริงของวัตถุตามสถานการณ์ปัจจุบัน สิ่งนี้เรียกว่าความหลากหลาย ความหลากหลายเป็นสิ่งสำคัญของการมุ่งเน้นเชิงวัตถุ
Polymorphism เป็นกลไกที่ได้รับการสนับสนุนโดย Java และยังเป็นแนวคิดเชิงวัตถุที่สำคัญอีกด้วย สิ่งนี้ทำให้เกิดคำถามอนุกรมวิธานว่าวัตถุคลาสย่อย "เป็น" วัตถุคลาสพาเรนต์จริงหรือไม่ ตัวอย่างเช่น นกก็เป็นสัตว์เช่นกัน รถยนต์ก็ต้องเป็นพาหนะด้วย Java บอกเราว่าคลาสอ็อบเจ็กต์ที่ได้รับสามารถใช้เป็นอ็อบเจ็กต์คลาสฐานได้ และ Java จะจัดการกับสถานการณ์นี้อย่างถูกต้อง
ตัวอย่างเช่น ความสัมพันธ์ทางมรดกต่อไปนี้:
เราสามารถพูดได้ว่าเราดื่มน้ำจากถ้วย ในความเป็นจริง ความหมายเฉพาะของการกระทำของน้ำดื่มจะเปลี่ยนไปอย่างมากในกลุ่มที่ได้รับ ตัวอย่างเช่น การดื่มน้ำผ่านหลอดและการดื่มน้ำจากแก้วที่แตกจะแตกต่างกันมาก แม้ว่าเราจะพูดถึง "น้ำดื่ม" ในเชิงนามธรรมก็ตาม แน่นอนว่าเราสามารถตั้งโปรแกรมแยกกันสำหรับแต่ละคลาสที่ได้รับและเรียกเมธอด drinkWater ที่แตกต่างกันได้ อย่างไรก็ตาม ในฐานะโปรแกรมเมอร์ เราสามารถตั้งโปรแกรม cup และเรียกใช้เมธอด drinkWater() ของ Cup โดยไม่คำนึงว่า Cup ที่ได้รับนั้นจะเป็นชนิดใดก็ตาม Java จะเรียกวิธีการที่ถูกต้องตามที่เราเห็นในโปรแกรมด้านบน
เมื่อดูตัวอย่างที่มีความหมายมากขึ้น เราได้เพิ่มเมธอด drink() ให้กับคลาส Human เมธอดนี้รับวัตถุถ้วยและจำนวนเต็มเป็นพารามิเตอร์ จำนวนเต็มแสดงถึงปริมาณน้ำที่จะดื่ม:
การทดสอบคลาสสาธารณะ { public static void main (String [] args) { Human guest = new Human (); BrokenCup hisCup = new BrokenCup (); guest.drink (hisCup, 10); }} คลาส Human { เป็นโมฆะเครื่องดื่ม (Cup aCup , int w) { aCup.drinkWater(w); }}
ผลการรันโปรแกรม:
อึไม่มีน้ำอยู่ข้างใน
ในคำจำกัดความของ drink() ของคลาส Human เราต้องการให้พารามิเตอร์แรกเป็นการอ้างอิงประเภท Cup แต่ในแอปพลิเคชันจริง (คลาสทดสอบ) จะใช้อ็อบเจ็กต์คลาสที่ได้รับ BrokenCup ของ Cup นี่เป็นการอัปแคสต์ hisCup ไปที่คลาส Cup และส่งต่อไปยังเมธอด drink() ในเมธอดนี้ เราเรียกเมธอด drinkWater() Java ค้นพบว่าวัตถุนี้จริงๆ แล้วเป็นวัตถุ BrokenCup ดังนั้นจึงเรียกว่าวิธีการที่สอดคล้องกันของ BrokenCup
ตกต่ำ
เราสามารถดาวน์คาสต์การอ้างอิงคลาสพื้นฐานไปยังการอ้างอิงคลาสที่ได้รับ แต่อ็อบเจ็กต์ที่ชี้ไปโดยการอ้างอิงคลาสฐานนั้นเป็นอ็อบเจ็กต์คลาสที่ได้รับที่จะถูกดาวน์คาสต์แล้ว ตัวอย่างเช่น hisCup ด้านบนสามารถเปลี่ยนขึ้นด้านบนเป็นการอ้างอิงคลาส Cup จากนั้นจึงแปลงลงด้านล่างเป็นการอ้างอิงคลาส BrokenCup
ประเภทวัตถุ
ใน Java คลาสทั้งหมดมีบรรพบุรุษที่สืบทอดร่วมกันซึ่งก็คือคลาส Object คลาส Object มีวิธีการบางอย่าง เช่น toString() เราสามารถแทนที่วิธีการเหล่านี้ได้ในคำจำกัดความของคลาสของเราเอง
วัตถุ: บรรพบุรุษ
เราสามารถเขียนโปรแกรมที่ดำเนินการออบเจ็กต์ Object และส่งผ่านออบเจ็กต์ใดๆ ไปยังโปรแกรมผ่านทางอัพคาสท์
ฉันจะเจาะลึกคลาส Object ในภายหลัง
(การนำความหลากหลายไปใช้นั้นต้องอาศัยการรองรับ RTTI ฉันจะอธิบายรายละเอียดเพิ่มเติมในภายหลัง)
สรุป
การแปลงประเภทพื้นฐาน
ความหลากหลาย
ตกต่ำ
วัตถุ