1. การพิมพ์
ตัวแปรที่เก็บประเภทการอ้างอิง (คลาส) ยังสามารถแปลงเป็นประเภทต่างๆ แต่สิ่งนี้ใช้ได้เฉพาะในลำดับชั้นประเภทเดียวเท่านั้น ลองดูตัวอย่างง่ายๆ สมมติว่าเรามีลำดับชั้นของคลาสต่อไปนี้ ซึ่งคลาสด้านล่างสืบทอดคลาสด้านบน
Typecasting ของประเภทการอ้างอิงเช่นเดียวกับประเภทดั้งเดิมนั้นยังจัดประเภทเป็นการขยายและการทำให้แคบลง
เราเห็นว่าคลาสแมวสืบทอดคลาสสัตว์เลี้ยง และคลาสสัตว์เลี้ยงก็สืบทอดคลาสสัตว์
ถ้าเราเขียนโค้ดดังนี้
Animal kitten = new Cat();
นี่คือการแปลงประเภทการขยับขยาย เรียกอีกอย่างว่าการส่งโดยปริยาย เราได้ขยาย การอ้างอิง catเพื่อให้ตอนนี้อ้างอิงถึงวัตถุCat ด้วยการแปลงประเภทเช่นนี้ เราจะไม่สามารถใช้ การอ้างอิง ลูกแมวเพื่อเรียกเมธอดที่มีอยู่ใน คลาส Catแต่ไม่มีอยู่ในคลาสAnimal
การแปลงที่แคบลง (หรือการโยนอย่างชัดเจน) เกิดขึ้นในทิศทางตรงกันข้าม:
Cat cat = (Cat) kitten;
เราระบุไว้อย่างชัดเจนว่าเราต้องการส่งการอ้างอิงที่จัดเก็บไว้ใน ตัวแปร ลูกแมว (ซึ่งมีประเภทคือAnimal ) ไปยังประเภทแมว
2. การตรวจสอบประเภทของวัตถุ
แต่คุณต้องระวังให้มากที่นี่ หากคุณทำเช่นนี้:
Animal beast = new Cat();
Wolf grayWolf = (Wolf) beast;
คอมไพเลอร์จะอนุญาตรหัสนี้ แต่จะมีข้อผิดพลาดเมื่อโปรแกรมทำงาน! JVM จะส่งข้อยกเว้น:
Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to a Wolf
การอ้างอิงถึง วัตถุ Catสามารถเก็บไว้ในตัวแปรประเภทที่เป็นบรรพบุรุษของคลาส Cat: Pet, Animal หรือ Object
ทำไมถึงเป็นเช่นนั้น?
ประเด็นที่เกี่ยวข้องในที่นี้คือการอ้างอิงวัตถุใช้เพื่ออ้างถึงวิธีการและตัวแปรของวัตถุนั้น และจะไม่มีปัญหาใดๆ หากเราใช้ตัวแปร Animal เพื่อจัดเก็บการอ้างอิงไปยังวัตถุ Cat: ประเภท Cat จะมีตัวแปรและเมธอดของประเภท Animal เสมอ — มันสืบทอดมา!
แต่ถ้า JVM อนุญาตให้เราจัดเก็บการอ้างอิงไปยังวัตถุ Cat ในตัวแปร Wolf เราอาจมีสถานการณ์ที่เราอาจลองใช้ตัวแปร greyWolf เพื่อเรียกเมธอดที่ไม่มีอยู่ในวัตถุ Cat ที่จัดเก็บไว้ในตัวแปรนั้น . นั่นเป็นเหตุผลที่ไม่อนุญาตการจัดการนี้
Java มีโอเปอเรเตอร์พิเศษinstanceof
ที่ให้คุณตรวจสอบว่าออบเจกต์เป็นประเภทใดประเภทหนึ่งหรือไม่ ดังนั้นจึงสามารถจัดเก็บไว้ในตัวแปรประเภทใดประเภทหนึ่งได้ มันดูค่อนข้างง่าย:
variable instanceof Type
ตัวอย่าง:
Animal beast = new Cat();
if (beast instanceof Wolf)
{
Wolf grayWolf = (Wolf) beast;
}
รหัสนี้จะไม่ทำให้เกิดข้อผิดพลาด — แม้ในขณะรันไทม์
ต่อไปนี้คือตัวอย่างเพิ่มเติมที่แสดงให้เห็นสถานการณ์:
การแปลงประเภทการขยับขยาย | คำอธิบาย |
---|---|
|
นี่เป็นการแปลงแบบขยายแบบคลาสสิก — ไม่จำเป็นต้องใช้ตัวดำเนินการแปลงประเภท ใน |
การแปลงประเภทที่แคบลง | |
|
การแปลงแบบคลาสสิกแคบลง:คุณต้องเพิ่มการตรวจสอบประเภทและตัวดำเนินการแคสต์ ตัวแปร Cow cow เก็บการอ้างอิงถึงWhale วัตถุ เราตรวจสอบว่าเป็นกรณีนี้จากนั้นทำการแปลงประเภท (จำกัดขอบเขต) หรือที่เรียกว่า:
ประเภทหล่อ
.
|
|
คุณสามารถจำกัดประเภทการอ้างอิงให้แคบลงโดยไม่ต้องตรวจสอบประเภทของวัตถุ หาก cow ตัวแปรอ้างอิงถึงอ็อบเจกต์ที่ไม่ใช่ a Whale ก็InvalidClassCastException จะถูกสร้างขึ้น |
3. เรียกใช้เมธอดเดิม: super
คำหลัก
เมื่อแทนที่เมธอดของคลาสพาเรนต์ บางครั้งแทนที่จะแทนที่ด้วยเมธอดของเราเอง เราเพียงต้องการเสริมเมธอดเล็กน้อยเท่านั้น
คงจะดีไม่น้อยหากเราสามารถเมธอดของคลาสพาเรนต์ในเมธอดของเราได้ แล้วรันโค้ดบางส่วนของเราเอง หรืออาจจะรันโค้ดของเราเองก่อน แล้วจึงเรียกเมธอดของคลาสพาเรนต์
และ Java ช่วยให้เราทำเช่นนั้นได้ ในการเรียกใช้เมธอดของคลาสพาเรนต์ ให้ทำดังนี้
super.method(arguments);
ตัวอย่าง:
class PeaceTime
{
public double getPi()
{
return 3.14;
}
}
class WarTime extends PeaceTime
{
public double getPi()
{
return super.getPi()*2; // 3.14*2
}
}
ในยามสงคราม ค่าของPi
อาจมากกว่า 6! แน่นอน เรากำลังล้อเล่น แต่ตัวอย่างนี้แสดงให้เห็นว่าทั้งหมดนี้ทำงานอย่างไร
ต่อไปนี้คือตัวอย่างเพิ่มเติมเพื่ออธิบายสิ่งต่างๆ เล็กน้อย:
รหัส | คำอธิบาย |
---|---|
|
Cow และWhale ชั้นเรียน |
|
เอาต์พุตหน้าจอจะเป็น:
|
นี่เป็นสิ่งที่ยาก จริงๆแล้วมันเป็นหนึ่งในสิ่งที่ยากที่สุดในOOP ที่กล่าวว่าคุณจำเป็นต้องรู้และเข้าใจ
GO TO FULL VERSION