Casting tra oggetti

Con il termine casting si intende la promozione implicita o esplicita delle variabili affinché possano restituire un risultato omogeneo nelle operazioni tra loro. Può infatti accadere che una variabile di tipo int debba essere sommata ad una variabile di tipo long (primitive widening) e via dicendo…Quando ciò accade uno dei membri dell’operazione viene promosso al formato più capiente affinché l’operazione possa essere compiuta e non vi siano perdite del dato. Tuttavia vi possono anche essere situazioni in cui questa operazione debba essere controllata allo scopo di ottenere il risultato voluto. E’ il caso del primitive narrowing ossia del restringimento del formato più capiente a quello meno capiente, che determina in questo caso una perdita di parte del dato.

Ma cosa accade quando tutto ciò deve essere fatto sulle classi e sugli oggetti?

Upcasting

Vi possono essere situazioni in cui una classe derivata debba essere convertita nella sua classe base, come nell’esempio seguente:

public class ClasseBase {
    /…/
}

public class ClasseDerivata extends ClasseBase {
    /.../
}

public static void main ( String [ ] args ) {
    ClasseBase identificatore = new ClasseDerivata;
}

Questo tipo di operazione comporta il restringimento della classe derivata alla classe base e può comportare la perdita dei metodi e delle variabili contenute nella classe derivata, tuttavia resta sempre possibile, in quanto la classe derivata condivide almeno parte della propria struttura con la classe base.

E’ altresì possibile convertire valori null e array in oggetti, o meglio, assegnare ad oggetti di classe Object i valori null o attribuire all’oggetto un array:

Object identificatore = null;
tipo identificatore_array [ ] = new tipo [ ];

Object identificatore_oggetto = identificatore_array;

Downcasting

Inverso il ragionamento legato al downcasting che deve essere esplicitato attraverso una particolare sintassi:

//Upcasting, con cui avevamo fatto l’upcasting ad una classe base

ClasseBase identificatore1 = new ClasseDerivata;

//Downcasting, con cui forziamo l’oggetto a rientrare nella classe derivata

ClasseDerivata identificatore2 = (ClasseBase) identificatore1;

In caso di omessa esplicitazione della sintassi di cui sopra riscontreremo un errore. Ciò accade perché non é cosa scontata che le due classi siano tra di essere compatibli e qualora non lo fossero avremo un errore di tipo Class CastException.

Anche in questo caso é possibile il downcasting da Object ad un array, riportando l’array nella sua forma originale:

Object identificatore_oggetto = new tipo[dimensione];
int [ ] identificatore_array = (int [ ]) identificatore_oggetto;

E’ possibile compiere la stessa operazione anche tra tipi differenti, purché l’operazione sia supportata dal linguaggio, ad esempio un array di interi può essere trasformata in un array di tipo long.

L’operatore instanceof

Dovesse mai servire di aver bisogno di conoscere il tipo di oggetto contenuto in una variabile l’operatore instanceof giunge in nostro soccorso. L’operatore instanceof restituisce true sia nel caso l’oggetto sia dello stesso tipo di quello indicato, sia nel caso sia un oggetto istanziato da una classe derivata.

TipoOggetto identificatore_oggetto = new TipoOggetto;

if ( identificatore_oggetto instanceof TipoOggetto) {
    /.../
}

Metodi e classi astratte

Tra le possibilità offerte da Java é doveroso menzionare anche la circostanza dell’astrazione di classi e metodi, vale a dirsi la loro prototipazione, utile a dichiararne l’esistenza salvo poi doverne definire attributi e metodi. Un metodo astratto può essere definito solo in una classe astratta, e questa classe non può essere direttamente istanziata bensì deve essere preliminarmente ridefinita in override.

Le classi astratte sono l’antitesi delle classi final e contrariamente a queste devono essere ridefinite. Le due keyword non possono essere presenti allo stesso tempo.

Le classi astratte rappresentano un aspetto molto importante di Java in quanto poggiano sull’idea di polimorfismo, concetto di base dal quale una stessa classe base (o in questo caso astratta) possa essere declinata in molteplici forme e per molteplici scopi. I metodi astratti possono essere contenuti sono nelle classi astratte.

public abstract class Tipo{
    public abstract void nomeMetodo( );
}

Le interfacce

Come si é detto il linguaggio Java prevede il solo concetto di ereditarietà singola, e ciò significa che é possibile estendere una sola classe per volta. Il problema viene parzialmente risolto dalle interfacce attraverso le quali si possono implementare infinite derivazioni. Le interfacce sono a tutti gli effetti delle classi astratte, che non possono essere istanziate, e al pari delle classi astratte non possono contenere codice salvo variabili che devono essere public, static e final, e metodi che sono astratti in modo predefinito. L’apposizione della keyword abstract davanti ai metodi é del tutto opzionale perché sottintesa. La definizione delle interfacce avviene attraverso la keyword riservata interface.

public interface nome_interfaccia {
    public static final String identificatore = “Stringa”;
    public abstract void nomeMetodo( );
}
public class Tipo implements nome_interfaccia {
    public void nomeMetodo( ) {
        /.../
    }
}

Luca Scandroglio

Sono un consulente tecnico informatico, un web designer e uno sviluppatore italiano. Aiuto le aziende a dotarsi degli strumenti tecnologici e digitali per superare le sfide del mercato di oggi.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *