Was ist der Unterschied zwischen Up-Casting und Down-Casting in Bezug auf die Klassenvariable?

138

Was ist der Unterschied zwischen Up-Casting und Down-Casting in Bezug auf die Klassenvariable?

Zum Beispiel in der folgenden Programmklasse enthält Animal nur eine Methode, aber die Dog-Klasse enthält zwei Methoden, wie wir dann die Dog-Variable in die Animal-Variable umwandeln.

Wenn das Casting abgeschlossen ist, wie können wir dann die andere Methode des Hundes mit der Variablen Animal aufrufen?

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();
    }
}
Dhivakar
quelle
A Dogist ein Animal. In den meisten Fällen ist ein Upcasting nicht erforderlich, es sei denn, Sie möchten eine bestimmte überladene Methode verwenden. callmeexistiert in beiden Animalund Dog. callme2nur existiert in Dog, was Sie werfen azu Dogmachen , um es zu arbeiten.
Brian
Was ist die Ausgabe Ihres Codes?
Malwinder Singh
Das Interessante ist, dass d.callme 'In callme of Dog' zurückgibt, obwohl d zum Tier gegossen wurde !!
Chris311
4
@ Chris311 Sowohl 'd' als auch 'a' zeigen auf dasselbe Objekt ... das ein Hund ist, aber 'a' hat nur Zugriff auf hundespezifische Methoden, wenn es zur Laufzeit heruntergekommen ist. Infact: Tier a = (Tier) d; ist unnötig, du brauchst nur Tier a = d; wie Sie upcasting.
Mark Keen

Antworten:

223

Upcasting wird in einen Supertyp umgewandelt, während Downcasting in einen Subtyp umgewandelt wird. Upcasting ist immer erlaubt, aber Downcasting beinhaltet eine Typprüfung und kann ein werfen ClassCastException.

In Ihrem Fall ist eine Besetzung von a Dognach a Animalein Upcast, weil a Dogis-a ist Animal. Im Allgemeinen können Sie Upcasts senden, wenn zwischen zwei Klassen eine Beziehung besteht.

Downcasting wäre ungefähr so:

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

Im Grunde , was Sie tun , ist es, den Compiler zu sagen , dass Sie wissen , was der Laufzeittyp des Objekts wirklich ist. Der Compiler lässt die Konvertierung zu, fügt jedoch weiterhin eine Laufzeitprüfung ein, um sicherzustellen, dass die Konvertierung sinnvoll ist. In diesem Fall ist die Umwandlung möglich, da zur Laufzeit animaltatsächlich eine Dog, obwohl der statische Typ von animalist Animal.

Wenn Sie dies jedoch tun würden:

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

Du würdest eine bekommen ClassCastException. Der Grund dafür ist, dass animalder Laufzeit-Typ ist Animal. Wenn Sie also der Laufzeit sagen, dass sie die Besetzung ausführen soll, sieht sie, dass dies animalnicht wirklich ein ist, Dogund wirft daher einen ClassCastException.

Um die Methode einer Oberklasse aufzurufen, können Sie dies tun super.method()oder den Upcast ausführen.

Um die Methode einer Unterklasse aufzurufen, müssen Sie einen Downcast durchführen. Wie oben gezeigt, riskieren Sie normalerweise ein Risiko, ClassCastExceptionindem Sie dies tun. Mit dem instanceofOperator können Sie jedoch den Laufzeittyp des Objekts überprüfen, bevor Sie die Umwandlung durchführen. Auf diese Weise können Sie verhindern, dass 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;
}
awksp
quelle
Stellt sicheres Downcasting sicher, dass dies nicht der Fall ist ClassCastExceptionoder nicht? Wie im ersten Fall?
Malwinder Singh
@MS Was meinst du mit "richtig"?
awksp
2
@awksp Dies ist eine ausgezeichnete und artikulierte Antwort. Fasst so ziemlich alles zusammen, was ich über Casting wissen muss.
Gautham Honnavara
Sie haben doch noch keinen Unterricht gemacht, in dem Tier ein Beispiel für Hund ist, oder? Warum suchst du überhaupt danach?
Barlop
62

Downcasting und Upcasting waren wie folgt:
Geben Sie hier die Bildbeschreibung ein

Upcasting : Wenn wir eine Unterklasse in eine Superklasse umwandeln möchten, verwenden wir Upcasting (oder Verbreiterung). Es geschieht automatisch, ohne dass explizit etwas unternommen werden muss.

Downcasting : Wenn wir eine Super-Klasse in eine Sub-Klasse umwandeln möchten, verwenden wir Downcasting (oder Verengung), und Downcasting ist in Java nicht direkt möglich, dies müssen wir explizit tun.

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
Premraj
quelle
Es gibt also keine Möglichkeit, Upcasting durchzuführen, um das übergeordnete Element der Methode aufzurufen.
Karlios
32

Upcasting und Downcasting sind wichtige Bestandteile von Java, die es uns ermöglichen, komplizierte Programme mit einfacher Syntax zu erstellen, und bieten uns große Vorteile wie Polymorphismus oder das Gruppieren verschiedener Objekte. Mit Java kann ein Objekt eines Unterklassentyps als Objekt eines beliebigen Oberklassentyps behandelt werden. Dies wird als Upcasting bezeichnet. Das Upcasting erfolgt automatisch, während das Downcasting manuell vom Programmierer durchgeführt werden muss , und ich werde mein Bestes geben, um zu erklären, warum das so ist.

Upcasting und Downcasting sind NICHT wie das Casting von Grundelementen von einem zum anderen, und ich glaube, das ist es, was viel Verwirrung stiftet, wenn der Programmierer anfängt, das Casting von Objekten zu lernen.

Polymorphismus: Alle Methoden in Java sind standardmäßig virtuell. Dies bedeutet, dass jede Methode bei der Vererbung überschrieben werden kann, es sei denn, diese Methode ist als endgültig oder statisch deklariert .

Im folgenden Beispiel sehen Sie, wie getType();je nach Objekttyp (Hund, Haustier, Polizeihund) funktioniert.

Angenommen, Sie haben drei Hunde

  1. Hund - Dies ist die Superklasse.

  2. Haustierhund - Haustierhund erweitert Hund.

  3. Polizeihund - Polizeihund erweitert Haustierhund.

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

Polymorphismus: Alle Methoden in Java sind standardmäßig virtuell. Dies bedeutet, dass jede Methode bei der Vererbung überschrieben werden kann, es sei denn, diese Methode ist als endgültig oder statisch deklariert. (Erläuterung gehört zum Konzept der virtuellen Tabellen)

Virtuelle Tabelle / Versandtabelle: Die Versandtabelle eines Objekts enthält die Adressen der dynamisch gebundenen Methoden des Objekts. Methodenaufrufe werden ausgeführt, indem die Adresse der Methode aus der Versandtabelle des Objekts abgerufen wird. Die Versandtabelle ist für alle Objekte derselben Klasse gleich und wird daher normalerweise von ihnen gemeinsam genutzt.

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

Druckt Normal Dog

  obj2.getType();

Druckt Pet Dog

 obj3.getType();

Druckt Police Dog

Das Downcasting muss vom Programmierer manuell durchgeführt werden

Wenn Sie versuchen, die secretID();Methode aufzurufen , für obj3die in der Hierarchie eine Superklasse angegeben ist PoliceDog object, auf die jedoch verwiesen wird, Dogwird ein Fehler ausgegeben, da obj3Sie keinen Zugriff auf die secretId()Methode haben. Um diese Methode aufzurufen, müssen Sie das Objekt manuell auf Downcast übertragen PoliceDog

  ( (PoliceDog)obj3).secretID();

welche druckt ID

Ähnlich wie beim Aufrufen der dogName();Methode in der PetDogKlasse, auf die Sie einen Downcast durchführen müssen obj2, PetDogda auf obj2 verwiesen wird Dogund Sie keinen Zugriff auf die dogName();Methode haben

  ( (PetDog)obj2).dogName();

Warum ist das so, dass das Upcasting automatisch erfolgt, das Downcasting jedoch manuell erfolgen muss? Sie sehen, Upcasting kann niemals scheitern. Aber wenn Sie eine Gruppe von verschiedenen Hunde haben und wollen sie alle ein , um ihre Typen niedergeschlagenen, dann gibt es eine Chance, dass einige dieser Hunde sind tatsächlich von verschiedenen Typen dh PetDog, PoliceDogund fehlschlägt, durch das Werfen ClassCastException.

Dies ist der Grund, warum Sie Ihre Objekte manuell herabstufen müssen, wenn Sie Ihre Objekte auf den Superklassentyp verwiesen haben.

Hinweis: Wenn Sie hier referenzieren, bedeutet dies, dass Sie die Speicheradresse Ihrer Objekte beim Downcasting nicht ändern. Sie bleiben jedoch unverändert. In diesem Fall gruppieren Sie sie nur nach einem bestimmten Typ Dog

Nagarjuna Yelisetty
quelle
"Polymorphismus verwendet bei Methodenaufrufen einen automatischen Downcast." Nein, tut es nicht. Der verwendete Mechanismus ist nicht spezifiziert, aber der üblichste Mechanismus - eine Tabelle - macht so etwas nicht. Schauen Sie in den Objektcode. Kein Niedergeschlagener.
Marquis von Lorne
Warum nicht? Dies ist, was richtig passiert. Können Sie ein Beispiel geben, bei dem es nicht funktioniert?
Nagarjuna Yelisetty
1
Warum nicht? Dies ist, was richtig passiert. Können Sie ein Beispiel geben, in dem die Anweisung "Polymorphismus verwendet automatischen Downcast während Methodenaufrufen". wird scheitern oder wird nicht zutreffen?
Nagarjuna Yelisetty
Es ist deine Behauptung. Es liegt an Ihnen, es zu beweisen. Zeigen Sie, wo im Objektcode der Downcast auftritt. Die Antwort auf die Frage "Warum nicht" lautet "Weil es nicht notwendig ist". Die vtable kümmert sich um den Methodenversand, und die Variable zeigt bereits auf das gesamte Objekt.
Marquis von Lorne
1
"Meines Wissens sind meine Aussagen wahr und es gilt in jedem Fall" ist kein Beweis. Es ist eine bloße Behauptung. Ich bitte Sie , Ihre Aussagen zu beweisen . Du machst das nicht. Tatsächlich wiederholen Sie sich nur. Und ich habe bereits mehrere Widerlegungen vorgelegt. Ich habe auch ein Entscheidungsverfahren bereitgestellt. Wenn Sie im Objektcode einen Downcast für einen Methodenaufruf finden, haben Sie Recht und ich liege falsch. So wird Wissenschaft gemacht. Tu es. Und zu behaupten, ich sei "mutig abhängig von der Dokumentation", ist eine offensichtliche Falschdarstellung. Tu das nicht.
Marquis von Lorne
12

Ich weiß, dass diese Frage vor ziemlich langer Zeit gestellt wurde, aber für die neuen Benutzer dieser Frage. Bitte lesen Sie diesen Artikel, der eine vollständige Beschreibung zum Upcasting, Downcasting und zur Verwendung der Instanz des Operators enthält

  • Es ist nicht erforderlich, manuell zu senden, es geschieht von selbst:

    Mammal m = (Mammal)new Cat(); ist gleich Mammal m = new Cat();

  • Downcasting muss jedoch immer manuell erfolgen:

    Cat c1 = new Cat();      
    Animal a = c1;      //automatic upcasting to Animal
    Cat c2 = (Cat) a;    //manual downcasting back to a Cat

Warum ist das so, dass das Upcasting automatisch erfolgt, das Downcasting jedoch manuell erfolgen muss? Sie sehen, Upcasting kann niemals scheitern. Wenn Sie jedoch eine Gruppe verschiedener Tiere haben und diese alle auf eine Katze herabstürzen möchten, besteht die Möglichkeit, dass einige dieser Tiere tatsächlich Hunde sind und der Prozess fehlschlägt, indem Sie ClassCastException auslösen. Hier sollte eine nützliche Funktion namens "instanceof" eingeführt werden , die testet, ob ein Objekt eine Instanz einer Klasse ist.

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

Für weitere Informationen lesen Sie bitte diesen Artikel

Nadeesha Thilakarathne
quelle
guter Punkt: Säugetier m = (Säugetier) neue Katze (); gleich Säugetier m = neue Katze ();
Catbuilts
6

Versuchen Sie diese Methode besser für das Upcasting, es ist leicht zu verstehen:

/* 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();
    }
}
UWAIS
quelle
und in der letzten Zeile könnte es sein: ((Hund) ref) .callme2 (); // für Downcasting / Narrowing und callme2 () Methodenzugriff der Dog Klasse.
udarH3
6

Vielleicht hilft dieser Tisch. Aufruf der callme()Methode der Klasse Parentoder Klasse Child. Grundsätzlich gilt:

UPCASTING -> Verstecken

DOWNCASTING -> Aufschlussreich

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Alexis
quelle
4

1.- Upcasting.

Bei einem Upcasting definieren Sie ein Tag eines Typs, das auf ein Objekt eines Subtyps verweist (Typ und Subtyp können als Klasse und Unterklasse bezeichnet werden, wenn Sie sich wohler fühlen ...).

Animal animalCat = new Cat();

Was bedeutet, dass ein solches Tag, animalCat, nur die Funktionalität (die Methoden) vom Typ Animal hat, da wir es als Typ Animal deklariert haben, nicht als Typ Cat.

Wir dürfen dies auf "natürliche / implizite / automatische" Weise tun, zur Kompilierungszeit oder zur Laufzeit, hauptsächlich weil Cat einen Teil seiner Funktionalität von Animal erbt. Zum Beispiel move (). (Zumindest ist Katze ein Tier, nicht wahr?)

2. Downcasting.

Aber was würde passieren, wenn wir die Funktionalität von Cat von unserem Typ Animal-Tag erhalten möchten?

Da wir das animalCat-Tag erstellt haben, das auf ein Cat-Objekt verweist, benötigen wir eine Möglichkeit, die Cat-Objektmethoden von unserem animalCat-Tag aus auf intelligente Weise aufzurufen.

Ein solches Verfahren nennen wir Downcasting und können es nur zur Laufzeit ausführen.

Zeit für Code:

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

}
Lemmy_Caution
quelle
2

Elternteil: Auto
Kind: Figo
Auto c1 = neues Figo ();

=====
Upcasting: -
Methode: Objekt c1 bezieht sich auf Methoden der Klasse (Figo - Methode muss überschrieben werden), da die Klasse "Figo" mit "new" angegeben ist.
Instanzvariable: Objekt c1 bezieht sich auf die Instanzvariable der Deklarationsklasse ("Auto").

Wenn die Deklarationsklasse übergeordnet ist und ein Objekt aus einem Kind erstellt wird, erfolgt ein implizites Casting, das "Upcasting" ist.

======
Downcasting: -
Figo f1 = (Figo) c1; //
Methode: Objekt f1 bezieht sich auf die Methode der Klasse (figo), da das ursprüngliche Objekt c1 mit der Klasse "Figo" erstellt wird. Sobald das Abwärtsgießen abgeschlossen ist, können Methoden, die nur in der Klasse "Figo" vorhanden sind, auch mit der Variablen f1 bezeichnet werden.
Instanzvariable: Objekt f1 bezieht sich nicht auf die Instanzvariable der Deklarationsklasse des Objekts c1 (Deklarationsklasse für c1 ist CAR), aber beim Downcasting bezieht es sich auf Instanzvariablen der Klasse Figo.

======
Verwendung: Wenn das Objekt zur untergeordneten Klasse gehört und die Deklarationsklasse übergeordnet ist und die untergeordnete Klasse auf die Instanzvariable ihrer eigenen Klasse und nicht der übergeordneten Klasse zugreifen möchte, kann dies mit "Downcasting" durchgeführt werden.

amit shah
quelle
1

Upcasting bedeutet, das Objekt in einen Supertyp umzuwandeln, während Downcasting das Umwandeln in einen Subtyp bedeutet.

In Java ist kein Upcasting erforderlich, da dies automatisch erfolgt. Und es wird normalerweise als implizites Casting bezeichnet. Sie können es angeben, um es anderen klar zu machen.

Also schreiben

Animal a = (Animal)d;

oder

Animal a = d;

führt zu genau der gleichen Stelle und in beiden Fällen wird die auszuführende callme()aus Dog.

Downcasting ist stattdessen erforderlich, da Sie aals Objekt von Animal definiert haben. Derzeit wissen Sie, dass es ein ist Dog, aber Java hat keine Garantie dafür. Eigentlich könnte es zur Laufzeit anders sein und Java wird ein werfen ClassCastException, würde das passieren. Natürlich ist dies bei Ihrem Beispiel nicht der Fall. Wenn Sie nicht werfen würde aauf Animal, java konnte nicht einmal die Anwendung kompiliert , da Animalkeine Methode haben callme2().

In Ihrem Beispiel können Sie nicht den Code erreichen callme()von Animalaus UseAnimlas(weil Dogüberschreiben) , es sei denn das Verfahren wie folgt sein würde:

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

Wir können ein Objekt für Downcasting erstellen. In diesem Typ auch. : Aufruf der Basisklassenmethoden

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