สวัสดีชาว Javarash ฉันเริ่มได้รับคำถามเกี่ยวกับประเภทการอ้างอิงการแคสต์ใน Java เพื่อไม่ให้เล่าซ้ำกันทุกครั้ง ฉันจึงตัดสินใจเขียนบทความสั้นๆ
มีการขยายตัวและการหดตัว เราจะเห็นว่าคลาสนั้นเป็น
ก่อนอื่นเรามาดูกันว่าการหล่อแบบใด
การหล่อประเภท (การแปลงประเภท)คือการแปลงค่าตัวแปรประเภทหนึ่งไปเป็นค่าประเภทอื่น มาดูตัวอย่างกันว่ามันคืออะไรและกินกับอะไร เรามีลำดับชั้นของคลาส ( ดูรูปที่ 1 ) ที่นี่คุณสามารถดูคลาสทั้งหมดของลำดับชั้น ใครสืบทอดใคร และวิธีการของแต่ละคลาสCat
ลูกหลานของคลาส ในทางกลับกันเป็น ผู้สืบทอดของคลาส เมื่อเราเขียน: Pet
Pet
Animal
Animal animalCat = new Cat();
Animal animalDog = new YorkshireTerrier();
นี่คือนักแสดงส่วนขยาย (หรือนักแสดงโดยนัย) เราได้ขยายลิงก์animalCat
และanimalDog
. พวกเขาอ้างถึงวัตถุCat
และDog
. ด้วยการใช้แบบนี้ เราไม่สามารถanimalCat/animalDog
เรียกเมธอดผ่านลิงก์ที่อยู่ในCat/Dog
, แต่อันที่ไม่ได้อยู่ในAnimal
. การหล่อ แบบแคบ (หรือชัดเจน) เกิดขึ้นในทิศทางตรงกันข้าม:
Animal animalCat = new Cat();
Animal animalDog = new YorkshireTerrier();
Cat cat =(Cat)animalCat;
YorkshireTerrier dog = (YorkshireTerrier) animalDog;
เราได้ระบุไว้อย่างชัดเจนว่าเราต้องการส่งวัตถุนี้ไปยังประเภทใด แต่ต้องระวัง!!! หากคุณทำเช่นนี้:
Animal animalCat = new Cat();
YorkshireTerrier dog = (YorkshireTerrier) animalCat;
คอมไพเลอร์จะข้ามโค้ดนี้ แต่RunTime
มันจะโยนออกมาให้คุณ:
Exception in thread "main" java.lang.ClassCastException: Animals.Cat cannot be cast to Animals.YorkshireTerrier
RunTime
เห็นว่าCat
มีYorkshireTerrier
สองคลาสที่แตกต่างกัน หากต้องการหลีกเลี่ยงClassCastExceptionในระหว่างการแปลงให้แคบลง ให้ใช้instanceof
.
Animal animalCat = new Cat();
if (animalCat instanceof YorkshireTerrier)
{
YorkshireTerrier dog = (YorkshireTerrier) animalCat;
}
หากanimalCat
เป็นเช่นYorkshireTerrier
นั้น งานมอบหมายก็จะเกิดขึ้น ถ้าไม่เช่นนั้นก็จะไม่มีอะไรเกิดขึ้น
เหตุใดจึงจำเป็นหากเราสูญเสียวิธีการและได้รับข้อผิดพลาดดังกล่าว
ลองดูโค้ดที่ผมสร้างตามแผนภาพในรูป 1 . ระดับAnimal
public abstract class Animal
{
String name;
int age;
String nameOfClass = getClass().getSimpleName();
public void eat(){
System.out.println(nameOfClass + ": Omnomnom");
}
public void sleep(){
System.out.println(nameOfClass + ": Z-z-z-z");
}
}
คลาสWildAnimal
ที่สืบทอดมาจากAnimal
public abstract class WildAnimal extends Animal
{
public void steelChicken()
{
System.out.println(nameOfClass+": Muhaha,I stole a chicken!");
}
}
คลาสPet
ที่สืบทอดมาจากAnimal
public abstract class Pet extends Animal
{
public void peeInTray(){
System.out.println(nameOfClass + ": Master, I peed");
}
}
คลาสFox
ที่สืบทอดมาจากWildAnimal
public class Fox extends WildAnimal
{
public void eatColobok(){
System.out.println(nameOfClass + ": I will eat you, Colobok");
}
}
คลาสWolf
ที่สืบทอดมาจากWildAnimal
public class Wolf extends WildAnimal
{
public void hawlAtTheMoon(){
System.out.println(nameOfClass + ": Ouuuuu!!!Ouuuu!!!");
}
}
คลาสCat
ที่สืบทอดมาจากPet
public class Cat extends Pet
{
public void sleepOnKeyboard(){
System.out.println(nameOfClass + ": Master, stop working!!I wanna sleep on your keyboard");
}
}
คลาสYorkshireTerrier
ที่สืบทอดมาจากPet
public class YorkshireTerrier extends Pet
{
public void bark(){
System.out.println(nameOfClass + ": Meow!!! Meow!!!");
}
}
ลองจินตนาการถึงสถานการณ์ เราจำเป็นต้องรวบรวมสัตว์ทั้งหมดไว้ในรายการเดียว ให้อาหารพวกมัน แล้วจึงพาพวกมันเข้านอน นี่เป็นเรื่องง่ายที่จะทำถ้าเราสร้างArrayList
สัตว์ ( Animal
) จากนั้นเราก็เรียกวิธีการที่สอดคล้องกันสำหรับสัตว์แต่ละตัว:
public class ZOO
{
public static void main(String[] args)
{
List<Animal> allAnimals = new ArrayList<>();
allAnimals.add(new Cat());
allAnimals.add(new Wolf());
allAnimals.add(new Fox());
allAnimals.add(new YorkshireTerrier());
for (Animal animal : allAnimals)
{
animal.eat();
animal.sleep();
}
}
}
ฉันไม่สามารถanimal
เรียกวิธีการbark()
หรือsleepOnKeyboard()
. เพราะในแผ่นallAnimals
ประกอบด้วยแมว หมาป่า โยริค และจิ้งจอก แต่พวกมันก็ถูกย่อให้Animal
เหลือ และมีเพียงวิธีการที่อยู่ในAnimal
. นี่เป็นสิ่งที่ดีมาก เพราะถ้าเราสามารถเรียกวิธีการทั้งหมดได้ แล้วทำไมเราถึงต้องการหมาป่าที่หลับบนคีย์บอร์ด หรือโยริคที่ขโมยไก่? ขอขอบคุณสำหรับความสนใจของคุณ. ฉันหวังว่าบทความนี้จะเป็นประโยชน์กับคุณ ยินดีรับคำติชมและติชม)
GO TO FULL VERSION