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


138

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

たとえば、次のプログラムクラスでは、Animalにはメソッドが1つしか含まれていませんが、Dogクラスには2つのメソッドが含まれているため、Dog変数をAnimal変数にキャストする方法を示しています。

キャストが行われたら、どうすればDogの別のメソッドをAnimalの変数で呼び出すことができますか。

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

A DogAnimalです。特定のオーバーロードメソッドを使用する場合を除き、ほとんどの場合、アップキャストは不要です。callme両方に存在するAnimalDogcallme2はにのみ存在しDog、機能させるためにキャストaしますDog
ブライアン

コードの出力は何ですか?
Malwinder Singh 2015

面白いのは、dが動物にキャストされたにもかかわらず、d.callmeが「In callme of Dog」を返すことです。
Chris311、2016年

4
@ Chris311は 'd'と 'a'の両方が同じオブジェクトを指します...これはDogですが、 'a'は実行時にダウンキャストされるときにDog固有のメソッドのみにアクセスできます。影響:動物a =(動物)d; 不必要です。動物a = dのみが必要です。あなたが予測しているように。
マークキーン

回答:


223

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

あなたの場合、a DogからanへのキャストAnimalは、a Dog-a なのでアップキャストAnimalです。一般に、2つのクラス間にis-a関係がある場合はいつでも、予測を変更できます。

ダウンキャストは次のようになります。

Animal animal = new Dog();
Dog castedDog = (Dog) animal;

基本的にあなたがやっていることは、オブジェクトの実行時の型が実際に何であるかを知っていることをコンパイラーに伝えることです。コンパイラは変換を許可しますが、変換が意味をなすことを確認するために実行時の健全性チェックを挿入します。この場合、静的型がisであっても、実行時にanimalは実際にはa であるため、キャストが可能です。DoganimalAnimal

ただし、これを行うとすると、

Animal animal = new Animal();
Dog notADog = (Dog) animal;

あなたは得るでしょうClassCastException。その理由animalAnimal、のランタイムタイプがであるため、ランタイムにキャストを実行するように指示animalするDogと、それは実際にはでないため、をスローするからClassCastExceptionです。

スーパークラスのメソッドを呼び出すにはsuper.method()、アップキャストを実行するか、実行します。

サブクラスのメソッドを呼び出すには、ダウンキャストを行う必要があります。上記のように、通常、ClassCastExceptionこれを行うとリスクが発生します。ただし、instanceofキャストを実行する前に、演算子を使用してオブジェクトの実行時のタイプを確認できます。これにより、ClassCastExceptions を防ぐことができます。

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;
}

適切なダウンキャスティングは、確実にないClassCastExceptionかどうかを保証しますか?最初のケースのように?
Malwinder Singh 2015

@MS「適切」とはどういう意味ですか?
awksp 2015

2
@awkspこれは優れた明確な答えです。キャスティングについて私が知っておく必要のあることをすべてまとめています。
Gautham Honnavara 2016年

確かにあなたは動物が犬のインスタンスであるクラスを作ったことはありませんか?なぜそれをチェックするのですか?
barlop 2017

62

ダウンキャストとアップキャストは次のとおりです。
ここに画像の説明を入力してください

アップキャスティングサブクラスをスーパークラスにキャストする場合は、アップキャスティング(または拡大)を使用します。これは自動的に行われ、明示的に何もする必要はありません。

ダウンキャスティング:スーパークラスをサブクラスにキャストする場合は、ダウンキャスティング(またはナローイング)を使用します。ダウンキャスティングは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

それで、メソッドの親を呼び出すためにアップキャストを行うそのような方法はありませんか?
karlihnos 2017

32

アップキャストとダウンキャストは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

ダウンキャストはプログラマが手動で行う必要があります

階層内のスーパークラスであるが参照さsecretID();obj3ているメソッドを呼び出そうとすると、メソッドにアクセスできないため、エラーがスローされます。そのメソッドを呼び出すには、obj3を手動でダウンキャストする必要があります。PoliceDog objectDogobj3secretId() PoliceDog

  ( (PoliceDog)obj3).secretID();

印刷する ID

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

  ( (PetDog)obj2).dogName();

なぜそうなるのですか、そのアップキャストは自動的ですが、ダウンキャストは手動でなければなりませんか?まあ、そうですね、アップキャストが失敗することはありません。あなたが別の犬のグループを持っており、すべてのタイプにそれらをダウンキャストしたい場合はしかし、その後、チャンスは、これらの犬のいくつかは、異なるタイプの実際にあること、あります、すなわちPetDogPoliceDog、およびプロセスが投げることで、失敗しましたClassCastException

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

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


「ポリモーフィズムは、メソッド呼び出し中に自動ダウンキャストを使用します。」いいえ、ありません。使用されるメカニズムは指定されていませんが、最も一般的なメカニズム(vtable)はそのようなことをしません。オブジェクトコードを見てください。ダウンキャストなし。
ローン侯爵

何故なの?これは正しく起こりますが、機能しない例を挙げられますか?
Nagarjuna Yelisetty 2015

1
何故なの?これが正しく実行されます。「ポリモーフィズムがメソッド呼び出し中に自動ダウンキャストを使用する」という例を挙げられますか?失敗するか、成り立たないのか?
Nagarjuna Yelisetty 2015

それはあなたの争いです。それを証明するのはあなた次第です。ダウンキャストが発生するオブジェクトコードの場所を示します。「なぜしないのか」という質問に対する答えは、「必要がないため」です。vtableはメソッドのディスパッチを処理し、変数はすでにオブジェクト全体を指しています。
ローンの侯爵

1
「私の知識によれば、私の発言は真実であり、すべての場合に当てはまります」は証明ではありません。それは単なる主張です。あなたの発言を証明するようにお願いします。あなたはそうしていません。事実、あなたは自分自身を繰り返すだけです。そして、私はすでにいくつかの反駁を提供しました。決定手順も提供しました。メソッド呼び出しのオブジェクトコードにダウンキャストが見つかれば、それは間違いではありません。これが科学のやり方です。やれ。そして、私が「ドキュメントに大胆に依存している」と主張するのは、露骨な不実表示です。しないでください。
ローンの侯爵

12

私はこの質問がかなり前に尋ねられたことを知っていますが、この質問の新しいユーザーのためです。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"と呼ばれる便利な機能を導入する場所です。

 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;
    }

詳細については、この記事をお読みください


良い点:哺乳類m =(哺乳類)new Cat(); Mammal m = new Cat();に等しい
Catbuiltは、16

6

アップキャストにはこの方法を試してみてください。簡単に理解できます。

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

そして、最後の行では次のようになります:((Dog)ref).callme2(); // Dogクラスのダウンキャスト/ナローイングおよびcallme2()メソッドアクセス用。
udarH3

6

多分この表が役立ちます。callme()class Parentまたはclassのメソッドを呼び出しChildます。原則として:

アップキャスティング->非表示

ダウンキャスティング->明らかにする

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください


4

1.-アップキャスト。

アップキャスティングを行うには、サブタイプのオブジェクトを指す、あるタイプのタグを定義します(タイプとサブタイプは、クラスとサブクラスと呼ばれることがあります...

Animal animalCat = new Cat();

このようなタグ、animalCatは、Catタイプではなく、Animalタイプとして宣言されているため、Animalタイプのみの機能(メソッド)を持つことになります。

主にCatがAnimalから一部の機能を継承しているため、コンパイル時または実行時に「自然/暗黙/自動」の方法でこれを行うことが許可されています。たとえば、move()です。(少なくとも、猫は動物ですよね?)

2.-ダウンキャスト。

しかし、タイプの動物タグから猫の機能を取得する必要がある場合はどうなりますか?

Catオブジェクトを指すanimalCatタグを作成したので、animalCatタグからスマートな方法でCatオブジェクトのメソッドを呼び出す方法が必要です。

このような手順は、ダウンキャストと呼ばれるものであり、実行時にのみ実行できます。

コードの時間:

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

}

2

親:車の
子:Figo
Car c1 = new Figo();

=====
アップキャスト: -
メソッド:オブジェクトc1はクラスのメソッドを参照します-クラス「フィーゴ」が「新」に指定されているので(フィーゴメソッドはオーバーライドする必要があります)。
インスタンス変数:オブジェクトc1は、宣言クラス( "Car")のインスタンス変数を参照します。

宣言クラスが親であり、オブジェクトが子で作成されている場合、「キャスト」である暗黙のキャストが発生します。

======
ダウンキャスト:
-Figo f1 =(Figo)c1; //
メソッド:最初のオブジェクトc1がクラス "Figo"で作成されるため、オブジェクトf1はクラス(figo)のメソッドを参照します。ただし、ダウンキャストが完了すると、クラス「Figo」にのみ存在するメソッドも変数f1で参照できます。
インスタンス変数:オブジェクトf1は、オブジェクトc1の宣言クラスのインスタンス変数を参照しません(c1の宣言クラスはCARです)が、ダウンキャストでは、クラスFigoのインスタンス変数を参照します。

======
使用:オブジェクトが子クラスで、宣言クラスが親で、子クラスが親クラスではなく、自身のクラスのインスタンス変数にアクセスする場合、「ダウンキャスト」で実行できます。


1

アップキャスティングはオブジェクトをスーパータイプにキャストすることを意味し、ダウンキャスティングはサブタイプにキャストすることを意味します。

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

したがって、

Animal a = (Animal)d;

または

Animal a = d;

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

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

あなたの例でcallme()は、メソッドが次のようにならない限り、(それを上書きするため)Animalfrom のコードに到達できません:UseAnimlasDog

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

0

ダウンキャストするオブジェクトを作成できます。このタイプでも。:基本クラスのメソッドを呼び出す

Animal a=new Dog();
a.callme();
((Dog)a).callme2();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.