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 = new Whale();

นี่เป็นการแปลงแบบขยายแบบคลาสสิก — ไม่จำเป็นต้องใช้ตัวดำเนินการแปลงประเภท Cowขณะนี้ สามารถเรียกเฉพาะเมธอดที่กำหนดใน คลาสบน Whaleออบเจกต์ได้

ในcowตัวแปรคอมไพเลอร์จะให้คุณเรียกใช้เมธอดที่ประเภท ( Cowคลาส) มี เท่านั้น

การแปลงประเภทที่แคบลง
Cow cow = new Whale();
if (cow instanceof Whale)
{
   Whale whale = (Whale) cow;
}
การแปลงแบบคลาสสิกแคบลง:คุณต้องเพิ่มการตรวจสอบประเภทและตัวดำเนินการแคสต์
ตัวแปรCow cowเก็บการอ้างอิงถึงWhaleวัตถุ
เราตรวจสอบว่าเป็นกรณีนี้จากนั้นทำการแปลงประเภท (จำกัดขอบเขต) หรือที่เรียกว่า:
ประเภทหล่อ
.

Cow cow = new Cow();
Whale whale = (Whale) cow; // Exception
คุณสามารถจำกัดประเภทการอ้างอิงให้แคบลงโดยไม่ต้องตรวจสอบประเภทของวัตถุ
หาก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! แน่นอน เรากำลังล้อเล่น แต่ตัวอย่างนี้แสดงให้เห็นว่าทั้งหมดนี้ทำงานอย่างไร

ต่อไปนี้คือตัวอย่างเพิ่มเติมเพื่ออธิบายสิ่งต่างๆ เล็กน้อย:

รหัส คำอธิบาย
class Cow
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor()
   {
      System.out.println("I'm a white whale");
   }

   public void printName()
   {
      System.out.println("I'm a cow");
   }
}

class Whale extends Cow
{
   public void printName()
   {
      System.out.print("This is incorrect: ");
      super.printName();
      System.out.println("I'm a whale");
   }
}
CowและWhaleชั้นเรียน
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
เอาต์พุตหน้าจอจะเป็น:
I'm a white whale
This is incorrect: I'm a cow
I'm a whale

นี่เป็นสิ่งที่ยาก จริงๆแล้วมันเป็นหนึ่งในสิ่งที่ยากที่สุดในOOP ที่กล่าวว่าคุณจำเป็นต้องรู้และเข้าใจ