web-dev-qa-db-ja.com

クラス変数に関してアップキャストとダウンキャストの違いは何ですか

クラス変数に関して、アップキャストとダウンキャストの違いは何ですか?

たとえば次のプログラムでは、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();
    }
}
115
Dhivakar

アップキャストはスーパータイプにキャストされ、ダウンキャストはサブタイプにキャストされます。アップキャストは常に許可されていますが、ダウンキャストは型チェックを伴い、ClassCastExceptionをスローする可能性があります。

あなたの場合では、DogからAnimalへのキャストはアップキャストです、なぜならDogAnimalであるからです。一般的に、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;
}
179
awksp

ダウンキャスティングおよびアップキャスティングは以下の通りであった。
enter image description here

アップキャスティング: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
48
Premraj

アップキャストとダウンキャストはJavaの重要な部分です。これにより、単純な構文を使用して複雑なプログラムを作成でき、多態性や異なるオブジェクトのグループ化などの大きな利点が得られます。 Javaでは、サブクラス型のオブジェクトを任意のスーパークラス型のオブジェクトとして扱うことができます。これはアップキャストと呼ばれます。アップキャストは自動的に行われますが、ダウンキャストはプログラマーによって手動で行われる必要があります、その理由を説明するために最善を尽くします。

アップキャストとダウンキャストは、あるプリミティブを別のプリミティブにキャストするのとは違います。プログラマーがオブジェクトのキャスティングを習得するようになると、混乱を招くことになります。

多態性:Javaのメソッドはすべてデフォルトで仮想です。つまり、そのメソッドがfinalまたはstaticとして宣言されていない限り、継承で使用されると、どのメソッドもオーバーライドできます。

以下の例で、getType();がオブジェクト(犬、ペット、警察犬)の種類によってどのように機能するかを見ることができます。

3匹の犬がいるとします

  1. 犬 - これはスーパークラスです。
  2. ペット犬 - ペット犬は犬を拡張します。
  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 objectsecretID();メソッドを呼び出そうとすると、obj3secretId()メソッドにアクセスできないためエラーが発生します。このメソッドを呼び出すには、obj3を手動でPoliceDogにダウンキャストする必要があります。

  ( (PoliceDog)obj3).secretID();

これはIDを印刷します

PetDogクラスでdogName();メソッドを呼び出すのと同じ方法で、obj2はPetDogを参照し、dogName();メソッドにアクセスできないため、obj2Dogにダウンキャストする必要があります。

  ( (PetDog)obj2).dogName();

アップキャストは自動的に行われますが、ダウンキャストは手動で行われる必要があるのはなぜですか。うーん、あなたは、アップキャストが失敗することは決してないのですね。しかし、あなたが異なるDogsのグループを持っていて、それらすべてをそれらの型にダウンキャストしたいのであれば、これらのDogsのいくつかは実際には異なる型、すなわちPetDogPoliceDog、である可能性があります。そしてClassCastExceptionを投げることによってプロセスは失敗します。

これが、オブジェクトをスーパークラス型に参照した場合は、オブジェクトを手動でダウンキャストする必要がある理由です

注:ここで参照するとは、オブジェクトのメモリアドレスをダウンキャストしても変更されないことを意味します。この場合は、それらを特定のタイプにグループ化しているだけですDog

30

私はこの質問がかなり以前に質問されたことを知っています、しかしこの質問の新しいユーザーのために。アップキャスト、ダウンキャスト、および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またはクラスChildcallme()メソッドを呼び出します。原則として:

予想外 - >非表示

ダウンロード - >表示

enter image description here

enter image description here

enter image description here

6
Alexis

アップキャストのためにこの方法を試してみた方がわかりやすいでしょう。

/* 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();
    }
}
6
UWAIS

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();

    }

}
4
Lemmy_Caution

親:車
子供:フィゴ
車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"を使用して実行できます。

2
amit shah

upcastingはオブジェクトをスーパータイプにキャストすることを意味し、downcastingはサブタイプにキャストすることを意味します。

Javaでは、自動的に行われるのでアップキャストは必要ありません。そしてそれは通常暗黙的キャストと呼ばれます。他の人にはっきりさせるためにそれを指定することができます。

したがって、書くこと

Animal a = (Animal)d;

または

Animal a = d;

まったく同じ点につながり、どちらの場合もDogからcallme()が実行されます。

aをAnimalのオブジェクトとして定義したので、代わりにダウンキャストが必要です。現在あなたはそれがDogであることを知っていますが、Javaはそれを保証しません。実際には実行時には違うかもしれず、JavaはClassCastExceptionを投げるでしょう、それは起こるでしょう。もちろん、それはあなたのまさにサンプル例のケースではありません。 aAnimalにキャストしないと、Animalにはメソッドcallme2()がないため、Javaはアプリケーションをコンパイルすることさえできません。

あなたの例では、メソッドが以下のようにならない限りAnimalからUseAnimlascallme()のコードに到達することはできません(Dogはそれを上書きするので):

class Dog extends Animal 
{ 
    public void callme()
    {
        super.callme();
        System.out.println("In callme of Dog");
    }
    ... 
} 
1
David

Downcastingに対するオブジェクトを作成することができます。このタイプでも。 :基本クラスのメソッドを呼び出す

Animal a=new Dog();
a.callme();
((Dog)a).callme2();
0
Rakesh