クラス変数に関して、アップキャストとダウンキャストの違いは何ですか?
たとえば次のプログラムでは、Animalクラスに含まれるメソッドは1つだけですが、Dogクラスには2つのメソッドが含まれています。次に、Dog変数をAnimal変数にキャストする方法を示します。
キャスティングが完了したら、どうやってAnimalの変数を使ってDogの他のメソッドを呼ぶことができるでしょう。
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class UseAnimlas
{
public static void main (String [] args)
{
Dog d = new Dog();
Animal a = (Animal)d;
d.callme();
a.callme();
((Dog) a).callme2();
}
}
アップキャストはスーパータイプにキャストされ、ダウンキャストはサブタイプにキャストされます。アップキャストは常に許可されていますが、ダウンキャストは型チェックを伴い、ClassCastException
をスローする可能性があります。
あなたの場合では、Dog
からAnimal
へのキャストはアップキャストです、なぜならDog
はAnimal
であるからです。一般的に、2つのクラスの間にis-a関係があるときはいつでもあなたはアップキャストすることができます。
ダウンキャストは次のようになります。
Animal animal = new Dog();
Dog castedDog = (Dog) animal;
基本的にあなたがしていることはあなたがオブジェクトの実行時型が何であるか知っていることをコンパイラに伝えることです 本当に です。コンパイラは変換を許可しますが、変換が意味をなすことを確認するために実行時健全性チェックを挿入します。この場合、animal
の静的型がDog
であっても、実行時にanimal
は実際にはAnimal
であるため、キャストが可能です。
しかし、あなたがこれをするとしたら:
Animal animal = new Animal();
Dog notADog = (Dog) animal;
あなたはClassCastException
を得るでしょう。その理由は、animal
のランタイム型がAnimal
なので、キャストを実行するようにランタイムに指示すると、animal
は実際にはDog
ではないことがわかり、したがってClassCastException
がスローされます。
スーパークラスのメソッドを呼び出すには、super.method()
またはupcastを実行します。
サブクラスのメソッドを呼び出すにはダウンキャストをする必要があります。上記のように、あなたは通常これを行うことによってClassCastException
を危険にさらします。ただし、キャストを実行する前にinstanceof
演算子を使用してオブジェクトの実行時型を確認することができます。これにより、ClassCastException
を防ぐことができます。
Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
// Guaranteed to succeed, barring classloader shenanigans
Dog castedDog = (Dog) animal;
}
ダウンキャスティングおよびアップキャスティングは以下の通りであった。
アップキャスティング:Subクラスをスーパークラスにキャストしたいときは、アップキャスティング(または拡大)を使います。自動的に行われます。明示的に何もする必要はありません。
Downcasting:SuperクラスをSubクラスにキャストしたい場合は、Downcasting(またはnarrowing)を使用します。DowncastingはJavaでは直接実行できないため、明示的に行う必要があります。
Dog d = new Dog();
Animal a = (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting
d.callme();
a.callme(); // It calls Dog's method even though we use Animal reference.
((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly.
// Internally if it is not a Dog object it throws ClassCastException
アップキャストとダウンキャストはJavaの重要な部分です。これにより、単純な構文を使用して複雑なプログラムを作成でき、多態性や異なるオブジェクトのグループ化などの大きな利点が得られます。 Javaでは、サブクラス型のオブジェクトを任意のスーパークラス型のオブジェクトとして扱うことができます。これはアップキャストと呼ばれます。アップキャストは自動的に行われますが、ダウンキャストはプログラマーによって手動で行われる必要があります、その理由を説明するために最善を尽くします。
アップキャストとダウンキャストは、あるプリミティブを別のプリミティブにキャストするのとは違います。プログラマーがオブジェクトのキャスティングを習得するようになると、混乱を招くことになります。
多態性:Javaのメソッドはすべてデフォルトで仮想です。つまり、そのメソッドがfinalまたはstaticとして宣言されていない限り、継承で使用されると、どのメソッドもオーバーライドできます。
以下の例で、getType();
がオブジェクト(犬、ペット、警察犬)の種類によってどのように機能するかを見ることができます。
3匹の犬がいるとします
警察犬 - 警察犬はペット犬を拡張します。
public class Dog{
public String getType () {
System.out.println("NormalDog");
return "NormalDog";
}
}
/**
* Pet Dog has an extra method dogName()
*/
public class PetDog extends Dog{
public String getType () {
System.out.println("PetDog");
return "PetDog";
}
public String dogName () {
System.out.println("I don't have Name !!");
return "NO Name";
}
}
/**
* Police Dog has an extra method secretId()
*/
public class PoliceDog extends PetDog{
public String secretId() {
System.out.println("ID");
return "ID";
}
public String getType () {
System.out.println("I am a Police Dog");
return "Police Dog";
}
}
多態性:Javaのすべてのメソッドはデフォルトで仮想です。つまり、継承で使用すると、そのメソッドがfinalまたはstaticとして宣言されていない限り、任意のメソッドをオーバーライドできます(仮想テーブルの概念に属します)。
仮想テーブル/ディスパッチテーブル:オブジェクトのディスパッチテーブルは、オブジェクトの動的にバインドされたメソッドのアドレスを含む。メソッド呼び出しは、オブジェクトのディスパッチテーブルからメソッドのアドレスを取得することによって実行されます。ディスパッチテーブルは、同じクラスに属するすべてのオブジェクトで同じなので、通常はそれらの間で共有されます。
public static void main (String[] args) {
/**
* Creating the different objects with super class Reference
*/
Dog obj1 = new Dog();
` /**
* Object of Pet Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry about it
*
*/
Dog obj2 = new PetDog();
` /**
* Object of Police Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry
* about it here even though we are extending PoliceDog with PetDog
* since PetDog is extending Dog Java automatically upcast for us
*/
Dog obj3 = new PoliceDog();
}
obj1.getType();
Normal Dog
を印刷します
obj2.getType();
Pet Dog
を印刷します
obj3.getType();
Police Dog
を印刷します
ダウンキャストはプログラマが手動で行う必要があります
obj3
であるが階層内のスーパークラスであるDog
を参照しているPoliceDog object
でsecretID();
メソッドを呼び出そうとすると、obj3
がsecretId()
メソッドにアクセスできないためエラーが発生します。このメソッドを呼び出すには、obj3を手動でPoliceDog
にダウンキャストする必要があります。
( (PoliceDog)obj3).secretID();
これはID
を印刷します
PetDog
クラスでdogName();
メソッドを呼び出すのと同じ方法で、obj2はPetDog
を参照し、dogName();
メソッドにアクセスできないため、obj2
をDog
にダウンキャストする必要があります。
( (PetDog)obj2).dogName();
アップキャストは自動的に行われますが、ダウンキャストは手動で行われる必要があるのはなぜですか。うーん、あなたは、アップキャストが失敗することは決してないのですね。しかし、あなたが異なるDogsのグループを持っていて、それらすべてをそれらの型にダウンキャストしたいのであれば、これらのDogsのいくつかは実際には異なる型、すなわちPetDog
、PoliceDog
、である可能性があります。そしてClassCastException
を投げることによってプロセスは失敗します。
これが、オブジェクトをスーパークラス型に参照した場合は、オブジェクトを手動でダウンキャストする必要がある理由です。
注:ここで参照するとは、オブジェクトのメモリアドレスをダウンキャストしても変更されないことを意味します。この場合は、それらを特定のタイプにグループ化しているだけです
Dog
私はこの質問がかなり以前に質問されたことを知っています、しかしこの質問の新しいユーザーのために。アップキャスト、ダウンキャスト、およびinstanceof演算子の使用に関する完全な説明が含まれているこの記事を読んでください
手動でアップキャストする必要はありません、それはそれ自身で起こります:
Mammal m = (Mammal)new Cat();
はMammal m = new Cat();
と同じです
しかし、ダウンキャストは常に手動で行わなければなりません。
Cat c1 = new Cat();
Animal a = c1; //automatic upcasting to Animal
Cat c2 = (Cat) a; //manual downcasting back to a Cat
アップキャストは自動的に行われますが、ダウンキャストは手動で行われる必要があるのはなぜですか。うーん、あなたは、アップキャストが失敗することは決してないのですね。しかし、あなたが異なる動物のグループを持っていて、それらすべてを猫に伏せたいのであれば、これらの動物のいくつかは実際には犬であり、ClassCastExceptionを投げて処理が失敗する可能性があります。これは "instanceof"と呼ばれる便利な機能を導入すべき場所です。これはオブジェクトがあるClassのインスタンスであるかどうかをテストします。
Cat c1 = new Cat();
Animal a = c1; //upcasting to Animal
if(a instanceof Cat){ // testing if the Animal is a Cat
System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure.");
Cat c2 = (Cat)a;
}
詳しくは、この記事を読んでください
たぶんこのテーブルは役立ちます。クラスParent
またはクラスChild
のcallme()
メソッドを呼び出します。原則として:
予想外 - >非表示
ダウンロード - >表示
アップキャストのためにこの方法を試してみた方がわかりやすいでしょう。
/* upcasting problem */
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class Useanimlas
{
public static void main (String [] args)
{
Animal animal = new Animal ();
Dog dog = new Dog();
Animal ref;
ref = animal;
ref.callme();
ref = dog;
ref.callme();
}
}
1.-アップキャスティング。
アップキャストを行うには、サブタイプのオブジェクトを指す、あるタイプのタグを定義します。あなたはより快適に感じる...)。
Animal animalCat = new Cat();
つまり、そのようなタグanimalCatは、タイプCatとしてではなくタイプAnimalとして宣言したので、タイプAnimalの機能(メソッド)のみを持つことになります。
Catがその機能の一部をAnimalから継承しているため、コンパイル時または実行時に、 "自然/暗黙/自動"の方法でこれを行うことができます。たとえば、move()です。 (少なくとも、猫は動物ですね。)
ダウンキャスト。
しかし、タイプAnimalタグからCatの機能を取得する必要がある場合はどうなりますか。
Catオブジェクトを指しているanimalCatタグを作成したので、私たちのanimalCatタグからCatオブジェクトのメソッドを呼び出すためのスマートな方法が必要です。
そのような手順は私達がDowncastingと呼ぶものであり、そして我々は実行時にのみそれを行うことができます。
いくつかのコードのための時間:
public class Animal {
public String move() {
return "Going to somewhere";
}
}
public class Cat extends Animal{
public String makeNoise() {
return "Meow!";
}
}
public class Test {
public static void main(String[] args) {
//1.- Upcasting
// __Type_____tag________object
Animal animalCat = new Cat();
//Some animal movement
System.out.println(animalCat.move());
//prints "Going to somewhere"
//2.- Downcasting
//Now you wanna make some Animal noise.
//First of all: type Animal hasn't any makeNoise() functionality.
//But Cat can do it!. I wanna be an Animal Cat now!!
//___________________Downcast__tag_____ Cat's method
String animalNoise = ( (Cat) animalCat ).makeNoise();
System.out.println(animalNoise);
//Prints "Meow!", as cats usually done.
//3.- An Animal may be a Cat, but a Dog or a Rhinoceros too.
//All of them have their own noises and own functionalities.
//Uncomment below and read the error in the console:
// __Type_____tag________object
//Cat catAnimal = new Animal();
}
}
親:車
子供:フィゴ
車c1 = new Figo();
=====
アップキャスト: -
メソッド:クラス "Figo"は "new"で指定されているため、オブジェクトc1はクラスのメソッドを参照します(Figo - メソッドをオーバーライドする必要があります)。
インスタンス変数:オブジェクトc1は宣言クラス( "Car")のインスタンス変数を参照します。
宣言クラスが親で、オブジェクトが子で作成されている場合、暗黙的キャストが発生します。これは「アップキャスト」です。
======
ダウンキャスト: -
フィゴーf1 =(フィゴー)c1。 //
メソッド:初期オブジェクトc1はクラス "Figo"で作成されるので、オブジェクトf1はクラスのメソッド(figo)を参照する。しかし一度ダウンキャストが行われると、クラス "Figo"にのみ存在するメソッドも変数f1によって参照されることができます。
インスタンス変数:オブジェクトf1はオブジェクトc1の宣言クラスのインスタンス変数を参照しません(c1の宣言クラスはCARです)が、ダウンキャストするとクラスFigoのインスタンス変数を参照します。
======
用途:ObjectがChild Classで、宣言クラスがParentで、Child classが、親クラスではなく、自身のクラスのInstance変数にアクセスしたい場合は、 "Downcasting"を使用して実行できます。
upcastingはオブジェクトをスーパータイプにキャストすることを意味し、downcastingはサブタイプにキャストすることを意味します。
Javaでは、自動的に行われるのでアップキャストは必要ありません。そしてそれは通常暗黙的キャストと呼ばれます。他の人にはっきりさせるためにそれを指定することができます。
したがって、書くこと
Animal a = (Animal)d;
または
Animal a = d;
まったく同じ点につながり、どちらの場合もDog
からcallme()
が実行されます。
a
をAnimalのオブジェクトとして定義したので、代わりにダウンキャストが必要です。現在あなたはそれがDog
であることを知っていますが、Javaはそれを保証しません。実際には実行時には違うかもしれず、JavaはClassCastException
を投げるでしょう、それは起こるでしょう。もちろん、それはあなたのまさにサンプル例のケースではありません。 a
をAnimal
にキャストしないと、Animal
にはメソッドcallme2()
がないため、Javaはアプリケーションをコンパイルすることさえできません。
あなたの例では、メソッドが以下のようにならない限りAnimal
からUseAnimlas
のcallme()
のコードに到達することはできません(Dog
はそれを上書きするので):
class Dog extends Animal
{
public void callme()
{
super.callme();
System.out.println("In callme of Dog");
}
...
}
Downcastingに対するオブジェクトを作成することができます。このタイプでも。 :基本クラスのメソッドを呼び出す
Animal a=new Dog();
a.callme();
((Dog)a).callme2();