Casting di classi

di il
7 risposte

Casting di classi

Salve, Sto studiando il casting tra le classi e non ho capito una cosa:

Cilindro cil=new Cilindro(4.0,10.0);
Cerchio cer;
Object obj;

cer=(Cerchio) cil;
obj=(Object) cil;
Ma la penultima istruzione la potevo evitare. Potevo scrivere direttamente l'ultima istruzione.

7 Risposte

  • Re: Casting di classi

    mark13 ha scritto:


    
    Cilindro cil=new Cilindro(4.0,10.0);
    Cerchio cer;
    Object obj;
    
    cer=(Cerchio) cil;
    obj=(Object) cil;
    
    Ma la penultima istruzione la potevo evitare. Potevo scrivere direttamente l'ultima istruzione.
    Il cast a Object è superfluo ... tutti gli oggetti derivano da Object.
    Se Cerchio è un supertipo di Cilindro, allora anche il cast a Cerchio è superfluo.

    Il cast con i tipi reference è di base abbastanza semplice (non tiriamo in ballo ora array e generics, per semplicità):
    - se vai verso un supertipo, il cast è superfluo (ma lecito). Il compilatore può già "provare" a livello di compilazione che il cast è corretto.
    - se vai verso un sottotipo, il cast è obbligatorio e impone che ci sia un check a runtime da parte della JVM.

    Naturalmente a meno che il compilatore possa già "provare" a priori che il cast non ha senso e non sarebbe mai realizzabile a runtime, nel qual caso è un errore di compilazione.
  • Re: Casting di classi

    Salve Andrea, quindi anche se avessi avuto la classe Figura al posto della classe Object potevo fare un casting direttamente da Cilindro verso Figura:
    
    Cilindro cil=new Cilindro(4.0, 10.0);
    Figura f=(Figura) cil;
    
    non rispettando la gerarchia delle classi, poiché Cerchio viene prima di Figura.
  • Re: Casting di classi

    mark13 ha scritto:


    Salve Andrea, quindi anche se avessi avuto la classe Figura al posto della classe Object potevo fare un casting direttamente da Cilindro verso Figura:
    
    Cilindro cil=new Cilindro(4.0, 10.0);
    Figura f=(Figura) cil;
    
    non rispettando la gerarchia delle classi, poiché Cerchio viene prima di Figura.
    Se Figura è supertipo di Cerchio e Cerchio è supertipo di Cilindro, quel cast è comunque superfluo. Figura sarebbe comunque un supertipo di Cilindro.

    Se ho capito bene la tua gerarchia, ovviamente.
  • Re: Casting di classi

    Ciao

    Non ho capito bene la domanda.
    Comunque, supponiamo di avere questa situazione (ne faccio una facile da capire):
    
    
    class Figura { }
    
    class Rettangolo extends Figura { }
    
    class Quadrato extends Rettangolo { }
    
    
    Abbiamo quindi definito la nostra gerarchia delle classi:
    • Una classe base di tipo Figura (implicitamente estende la classe Object)
    • Una classe Rettangolo che di fatto è un tipo particolare di Figura
    • Una classe Quadrato che è un tipo particolare di Rettangolo (coi lati uguali) e di conseguenza è anche un tipo particolare di Figura

    Avendo definito questa struttura, possiamo definire che:
    • Qualsiasi oggetto di tipo Quadrato può essere utilizzato se richiesto un Quadrato, un Rettangolo, una Figura o un Object
    • Qualsiasi oggetto di tipo Rettangolo può essere utilizzato se richiesto un Rettangolo, una Figura o un Object. Non può invece essere utilizzato se è richiesto un oggetto di tipo Quadrato (occorre farne una conversione)
    • Qualsiasi oggetto di tipo Figura può essere utilizzato se richiesta una Figura o un Object. Non può invece essere utilizzato se è richiesto un Quadrato o un Rettangolo (occorre farne una conversione)

    Spero che questo esempio abbia chiarito il tuo problema.
  • Re: Casting di classi

    PiGi78 ha scritto:


    
    class Quadrato extends Rettangolo { }
    
    Solo un piccolo appunto, per correttezza: Quadrato extends Rettangolo è una estensione notoriamente "critica". Dipende anche da cosa fanno le classi ma se Rettangolo è "mutabile" ed ha setLarghezza() e setAltezza(), la estensione è sbagliata poiché il concetto di Quadrato pone una restrizione che viola il principio di sostituibilità degli oggetti.

    Se Rettangolo e Quadrato fossero immutabili, allora sì, è appropriato.
  • Re: Casting di classi

    Ciao a tutti, Si ho capito. Il mio dubbio era se rispettare la gerarchia oppure no. In pratica se dovevo fare un casting da un istanza della classe Cilindro alla classe Figura pensavo che non potevo farlo direttamente. Credevo che prima dovevo fare il cast da un istanza della classe Cilindro alla classe Cerchio, ed infine dall'istanza della classe Cerchio alla classe Figura:
    
    Cilindro cil= new Cilindro(4.0, 10.0);
    Cerchio cer=(Cerchio) cil;
    Figura f=(Figura) cer;
    
    Ma come dici andbin è inutile fare l'upcasting di una istanza della classe Cilindro alla classe Figura, poiché l'istanza della classe Cilindro, per la relazione di ereditarietà, eredita tutti i metodi della classe Cerchio, e quindi di conseguenza anche tutti i metodi della classe Figura.

    Invece se dovevo fare il downcasting potevo semplicemente scrivere così:

    
    Figura f=(Figura)(new Cilindro(4.0, 10.0));
    Cilindro cil=(Cilindro) f;
    
    dato che l'oggetto f non è solo un istanza della classe Figura ma è anche un istanza della classe Cilindro.
  • Re: Casting di classi

    Data la gerarchia (c'è anche una interfaccia come esempio):
    interface SuperficieCalcolabile {
        double calcolaSuperficie();
    }
    
    abstract class Solido implements SuperficieCalcolabile { /*blabla*/ }
    
    class Cubo extends Solido { /*blabla e implementazione di calcolaSuperficie()*/ }
    class Sfera extends Solido { /*blabla e implementazione di calcolaSuperficie()*/ }
    A fronte di:
    Sfera sfera1 = new Sfera( ....... );
    TUTTI i seguenti assegnamenti sono leciti e funzionanti:
    Solido s = sfera1;
    SuperficieCalcolabile sc = sfera1;
    Object o = sfera1;
    Non c'è bisogno di mettere un cast esplicito (tipo) (metterlo è comunque lecito) perché i tipi delle 3 variabili sono super-tipi di Sfera. Questo il compilatore "lo sa" dalle definizioni dei tipi e mette un up-cast implicito, che è assolutamente innocuo e non causa alcun check a runtime.

    Il down-cast invece è "controllato" a runtime.
    SuperficieCalcolabile sc = new Sfera( ....... );
    
    Sfera sf = (Sfera) sc;    // Ok
    Questo cast è obbligatorio perché Sfera è un sotto-tipo di SuperficieCalcolabile. Il cast è lecito per il compilatore perché Sfera è in relazione con SuperficieCalcolabile. Detto in altro modo, il compilatore "sa" che una variabile di tipo SuperficieCalcolabile potrebbe fare riferimento ad un oggetto Sfera.
    C'è però un check a runtime in cui la JVM verifica materialmente: "l'oggetto referenziato da sc è realmente un Sfera?". In questo caso sì, quindi il cast ha successo e sf farà riferimento all'oggetto Sfera che puoi usare in seguito.

    MA
    SuperficieCalcolabile sc = new Cubo( ....... );
    
    Sfera sf = (Sfera) sc;     // ti becchi ClassCastException a runtime
    Anche questo è lecito per il compilatore, ma il cast a runtime fallisce, perché l'oggetto realmente è di tipo Cubo, NON Sfera.
Devi accedere o registrarti per scrivere nel forum
7 risposte