Qual è la differenza tra up-casting e down-casting rispetto alla variabile di classe


138

Qual è la differenza tra up-casting e down-casting rispetto alla variabile di classe?

Ad esempio, nella seguente classe di programmi Animale contiene solo un metodo, ma la classe Cane contiene due metodi, quindi il modo in cui lanciamo la variabile Dog nella variabile Animale.

Se il casting viene eseguito, come possiamo chiamare un altro metodo del cane con la variabile 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 Dogè un Animal. La maggior parte delle volte l'upgrade non è necessario a meno che non si desideri utilizzare un determinato metodo sovraccarico. callmeesiste in entrambi Animale Dog. callme2esiste solo in Dog, che si esegue il cast aper Dogper farlo funzionare.
Brian,

Qual è l'output del tuo codice?
Malwinder Singh,

La cosa interessante è che d.callme restituisce 'In callme of Dog' anche se d è stato lanciato sull'animale !!
Chris311,

4
@ Chris311 sia 'd' che 'a' puntano allo stesso oggetto ... che è un cane, ma 'a' ha accesso solo ai metodi specifici del cane quando viene scaricato in fase di esecuzione. Infatti: Animale a = (Animale) d; non è necessario, hai solo bisogno di Animal a = d; mentre stai upcasting.
Mark Keen,

Risposte:


223

L'upcasting sta lanciando su un supertipo, mentre il downcasting sta lanciando su un sottotipo. L'upgrade è sempre consentito, ma il downcast comporta un controllo del tipo e può generare un ClassCastException.

Nel tuo caso, un cast da a Doga an Animalè un upcast, perché a Dogis-a Animal. In generale, puoi effettuare l'upgrade ogni volta che esiste una relazione is-a tra due classi.

Il downcasting sarebbe qualcosa del genere:

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

Fondamentalmente quello che stai facendo è dire al compilatore che si sa che cosa il tipo di esecuzione dell'oggetto in realtà è. Il compilatore consentirà la conversione, ma inserirà comunque un controllo di integrità del runtime per assicurarsi che la conversione abbia senso. In questo caso, il cast è possibile perché in fase di esecuzione animalè in realtà una Doganche se il tipo statico animalè Animal.

Tuttavia, se dovessi farlo:

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

Avresti ottenuto un ClassCastException. Il motivo è perché animalil tipo di runtime è Animal, e quindi quando dici al runtime di eseguire il cast, vede che animalnon è realmente un Doge quindi lancia un ClassCastException.

Per chiamare il metodo di una superclasse puoi fare super.method()o eseguendo l'upcast.

Per chiamare il metodo di una sottoclasse devi fare un downcast. Come mostrato sopra, normalmente si rischia a ClassCastExceptionfacendo questo; tuttavia, è possibile utilizzare l' instanceofoperatore per verificare il tipo di runtime dell'oggetto prima di eseguire il cast, il che consente di impedire 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;
}

Il downcasting corretto garantisce no ClassCastExceptiono no? Come nel primo caso?
Malwinder Singh,

@MS Cosa intendi con "corretto"?
awksp,

2
@awksp Questa è una risposta eccellente e articolata. Riassume praticamente tutto ciò che devo sapere sul Casting.
Gautham Honnavara,

sicuramente non hai fatto lezioni in cui l'animale è un'istanza di cane, vero? quindi perché lo stai verificando?
barlop

62

Down-casting e up-casting sono stati i seguenti:
inserisci qui la descrizione dell'immagine

Upcasting : quando vogliamo trasmettere una sottoclasse alla classe super, utilizziamo l'upcasting (o l'ampliamento). Succede automaticamente, non c'è bisogno di fare nulla di esplicito.

Downcasting : quando vogliamo trasmettere una classe Super alla sottoclasse, utilizziamo il downcasting (o il restringimento) e il downcasting non è direttamente possibile in Java, esplicitamente dobbiamo farlo.

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

Quindi, non esiste un modo di fare upcasting per chiamare il genitore del metodo?
karlihnos,

32

L'upgrade e il downcasting sono una parte importante di Java, che ci consente di creare programmi complicati utilizzando una sintassi semplice e ci offre grandi vantaggi, come il polimorfismo o il raggruppamento di oggetti diversi. Java consente a un oggetto di un tipo di sottoclasse di essere trattato come un oggetto di qualsiasi tipo di superclasse. Questo si chiama upcasting. L'upcasting viene eseguito automaticamente, mentre il downcasting deve essere eseguito manualmente dal programmatore e sto per dare il massimo per spiegare perché.

L'upcasting e il downcasting NON sono come il lancio di primitive dall'una all'altra, e credo che questo sia ciò che provoca molta confusione, quando il programmatore inizia a imparare a lanciare oggetti.

Polimorfismo: tutti i metodi in Java sono virtuali per impostazione predefinita. Ciò significa che qualsiasi metodo può essere ignorato se utilizzato in eredità, a meno che tale metodo non sia dichiarato come definitivo o statico .

Di seguito puoi vedere come getType();funziona in base al tipo di oggetto (Cane, Animale domestico, Cane poliziotto).

Supponi di avere tre cani

  1. Cane - Questa è la super classe.

  2. Pet Dog - Pet Dog estende Dog.

  3. Cane poliziotto - Cane poliziotto estende il cane da compagnia.

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

Polimorfismo: tutti i metodi in Java sono virtuali per impostazione predefinita. Ciò significa che qualsiasi metodo può essere ignorato se utilizzato in eredità, a meno che tale metodo non sia dichiarato come definitivo o statico (Spiegazione appartiene al concetto di tabelle virtuali)

Tabella virtuale / Tabella di invio: la tabella di invio di un oggetto conterrà gli indirizzi dei metodi associati dinamicamente all'oggetto. Le chiamate al metodo vengono eseguite recuperando l'indirizzo del metodo dalla tabella di invio dell'oggetto. La tabella di invio è la stessa per tutti gli oggetti appartenenti alla stessa classe ed è quindi generalmente condivisa tra di loro.

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

stampe Normal Dog

  obj2.getType();

stampe Pet Dog

 obj3.getType();

stampe Police Dog

Il downcasting deve essere eseguito manualmente dal programmatore

Quando si tenta di invocare il secretID();metodo su obj3cui si fa PoliceDog objectriferimento ma Dogche è una super classe nella gerarchia, viene generato un errore poiché obj3non si ha accesso al secretId()metodo. Per invocare quel metodo è necessario eseguire il Downcast di obj3 manualmente PoliceDog

  ( (PoliceDog)obj3).secretID();

quale stampa ID

In modo simile a invocare il dogName();metodo nella PetDogclasse che si bisogno di downcast obj2al PetDogdato obj2 è riferito a Doge non hanno accesso a dogName();metodo

  ( (PetDog)obj2).dogName();

Perché è così, che l'upcasting è automatico, ma il downcasting deve essere manuale? Bene, vedi, l'upgrade non può mai fallire. Ma se si dispone di un gruppo di diversi cani e vuole a tutti loro downcast ad un a loro tipi, poi c'è una possibilità, che alcuni di questi cani sono in realtà di diversi tipi IE, PetDog, PoliceDog, e il processo fallisce, lanciando ClassCastException.

Questo è il motivo per cui devi eseguire il downcast manuale dei tuoi oggetti se hai fatto riferimento ai tuoi oggetti al tipo di superclasse.

Nota: qui facendo riferimento significa che non stai modificando l'indirizzo di memoria dei tuoi oggetti espulsi quando lo annulli, rimane sempre lo stesso, li stai solo raggruppando in un tipo particolare in questo caso Dog


"Il polimorfismo utilizza il downcast automatico durante le chiamate di metodo." No non lo fa. Il meccanismo usato non è specificato, ma il meccanismo più usuale - una tabella - non fa nulla del genere. Cerca nel codice oggetto. Nessun downcast.
Marchese di Lorne,

Perchè no? Questo è ciò che succede, puoi fare un esempio in cui non funzionerà?
Nagarjuna Yelisetty,

1
Perchè no? Questo è ciò che accade nel modo giusto ... puoi fare un esempio in cui l'affermazione "Il polimorfismo usa il downcast automatico durante le chiamate di metodo". fallirà o non sarà vero?
Nagarjuna Yelisetty,

È la tua contesa. Sta a te dimostrarlo. Mostra dove nel codice oggetto si verifica il downcast. La risposta alla domanda "perché no" è "perché non è necessaria". La vtable si occupa dell'invio del metodo e la variabile punta già all'intero oggetto.
Marchese di Lorne,

1
"Per quanto ne so, le mie affermazioni sono vere e valide in ogni caso" non è una prova. È una semplice affermazione. Chiedo che si per dimostrare le vostre dichiarazioni. Non lo stai facendo. In effetti, ti stai solo ripetendo. E ho già fornito diverse confutazioni. Ho anche fornito una procedura decisionale. Se riesci a trovare un downcast nel codice oggetto per una chiamata di metodo, hai ragione e sbaglio. Ecco come si fa la scienza. Fallo. E affermare che sono "coraggiosamente dipendente dalla documentazione" è una palese dichiarazione falsa. Non farlo.
Marchese di Lorne,

12

So che questa domanda è stata posta molto tempo fa ma per i nuovi utenti di questa domanda. Si prega di leggere questo articolo in cui contiene una descrizione completa di upcasting, downcasting e utilizzo dell'istanza dell'operatore

  • Non è necessario eseguire l'upgrade manuale, succede da solo:

    Mammal m = (Mammal)new Cat(); è uguale a Mammal m = new Cat();

  • Ma il downcasting deve sempre essere eseguito manualmente:

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

Perché è così, che l'upcasting è automatico, ma il downcasting deve essere manuale? Bene, vedi, l'upgrade non può mai fallire. Ma se hai un gruppo di animali diversi e vuoi abbatterli tutti su un gatto, allora c'è una possibilità che alcuni di questi animali siano in realtà cani e che il processo fallisca, lanciando ClassCastException. Qui è dove dovrebbe introdurre un'utile funzione chiamata "instanceof" , che verifica se un oggetto è un'istanza di una classe.

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

Per maggiori informazioni leggi questo articolo


buon punto: Mammal m = (Mammal) new Cat (); è uguale a Mammal m = new Cat ();
Catbuilts

6

Meglio provare questo metodo per l'upgrade, è facile da capire:

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

e nell'ultima riga potrebbe essere: ((Dog) ref) .callme2 (); // per downcast / restringimento e accesso al metodo callme2 () della classe Dog.
udarH3

6

Forse questa tabella aiuta. Chiamare il callme()metodo di classe Parento classe Child. In linea di principio:

UPCASTING -> Nascondersi

DOWNCASTING -> Rivelazione

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


4

1.- Upcasting.

Facendo un upcasting, si definisce un tag di qualche tipo, che punta a un oggetto di un sottotipo (Tipo e sottotipo possono essere chiamati classe e sottoclasse, se ci si sente più a proprio agio ...).

Animal animalCat = new Cat();

Ciò significa che tale tag, animalCat, avrà la funzionalità (i metodi) solo di tipo Animale, perché lo abbiamo dichiarato come tipo Animale, non come tipo Gatto.

Ci è permesso farlo in modo "naturale / implicito / automatico", in fase di compilazione o in fase di esecuzione, principalmente perché Cat eredita parte delle sue funzionalità da Animal; ad esempio, move (). (Almeno, il gatto è un animale, no?)

2.- Downcasting.

Ma cosa accadrebbe se avessimo bisogno della funzionalità di Cat, dal nostro tag Animal ?.

Dato che abbiamo creato il tag animalCat che punta a un oggetto Cat, abbiamo bisogno di un modo per chiamare i metodi dell'oggetto Cat, dal nostro tag animalCat in un modo piuttosto intelligente.

Tale procedura è ciò che chiamiamo Downcasting e possiamo farlo solo in fase di esecuzione.

Tempo per un po 'di codice:

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

Parent: Car
Child: Figo
Car c1 = new Figo ();

=====
Upcasting: -
Metodo: l'oggetto c1 farà riferimento a Metodi di classe (Figo - Il metodo deve essere ignorato) poiché la classe "Figo" è specificata con "nuovo".
Variabile di istanza: l'oggetto c1 farà riferimento alla variabile di istanza della classe di dichiarazione ("Automobile").

Quando la classe di dichiarazione è padre e l'oggetto viene creato da figlio, si verifica il cast implicito che è "Upcasting".

======
Downcasting: -
Figo f1 = (Figo) c1; //
Metodo: l'oggetto f1 farà riferimento al metodo della classe (figo) come l'oggetto iniziale c1 viene creato con la classe "Figo". ma una volta eseguito il down casting, i metodi presenti solo nella classe "Figo" possono anche essere indicati dalla variabile f1.
Variabile di istanza: l'oggetto f1 non farà riferimento alla variabile di istanza della classe di dichiarazione dell'oggetto c1 (la classe di dichiarazione per c1 è CAR) ma con il down casting farà riferimento alle variabili di istanza della classe Figo.

======
Uso: quando Object è di classe Child e la classe di dichiarazione è Parent e la classe Child desidera accedere alla variabile Instance della propria classe e non della classe parent, allora può essere eseguita con "Downcasting".


1

upcasting significa lanciare l'oggetto su un sottotipo, mentre downcasting significa lanciare su un sottotipo.

In java, l'upgrade non è necessario poiché viene eseguito automaticamente. E di solito viene definito casting implicito. Puoi specificarlo per renderlo chiaro agli altri.

Quindi, scrivendo

Animal a = (Animal)d;

o

Animal a = d;

porta esattamente allo stesso punto e in entrambi i casi verrà eseguito il callme()da Dog.

Il downcasting è invece necessario perché definito acome oggetto di Animal. Attualmente sai che è un Dog, ma Java non ha garanzie che lo sia. In realtà in fase di esecuzione potrebbe essere diverso e java lancerà un ClassCastException, sarebbe successo. Ovviamente non è il caso del tuo esempio. Se non si desidera lanciare aa Animal, java non riusciva nemmeno a compilare l'applicazione in quanto Animalnon dispone di metodo callme2().

Nel tuo esempio, non è possibile raggiungere il codice di callme()di Animalda UseAnimlas(perché Dogsovrascrittura di esso) a meno che sarebbe il metodo come segue:

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

0

Possiamo creare oggetti per il downcasting. Anche in questo tipo. : chiamando i metodi della classe base

Animal a=new Dog();
a.callme();
((Dog)a).callme2();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.