こんにちは、ジャバラッシュさん。Java での参照型のキャストに関する質問を受けるようになりました。毎回同じことを言わないように、短い記事を書くことにしました。
まず、型キャストとは何かを見てみましょう。
型キャスト (型変換) は、ある型の変数値を別の型の値に変換することです。それが何であるか、そしてそれが何と一緒に食べられるかの例を見てみましょう。いくつかのクラス階層があります (図 1 を参照)。ここでは、階層のすべてのクラス、誰が誰を継承するか、および各クラスのメソッドを確認できます。 拡張する内転と収縮する内転があります。Cat
このクラスが class の子孫であることがわかります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
2 つの異なるクラスがあることがわかります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!!!");
}
}
状況を想像してみてください。すべての動物を 1 つのリストに集め、餌をあげてから寝かせる必要があります。動物を作成すると、これを簡単に行うことができます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