Casting di variabili in Java


84

Mi chiedo se qualcuno possa dirmi come funziona il casting? Capisco quando dovrei farlo, ma non proprio come funziona. Sui tipi di dati primitivi capisco parzialmente ma quando si tratta di trasmettere oggetti non capisco come funziona.

Come può un oggetto con il tipo Object essere lanciato improvvisamente, diciamo, MyType(solo un esempio) e quindi ottenere tutti i metodi?


Letture consigliate: Eredità
spugna

Risposte:


182

Il casting in Java non è magico, stai dicendo al compilatore che un Object di tipo A è in realtà di tipo B più specifico, ottenendo così l'accesso a tutti i metodi su B che altrimenti non avresti avuto. Non stai eseguendo alcun tipo di magia o conversione quando esegui il casting, essenzialmente stai dicendo al compilatore "fidati di me, so cosa sto facendo e posso garantirti che questo oggetto su questa riga è in realtà un <Inserisci cast digita qui>. " Per esempio:

Object o = "str";
String str = (String)o;

Quanto sopra va bene, non magico e va bene. L'oggetto memorizzato in o è in realtà una stringa, quindi possiamo eseguire il cast su una stringa senza problemi.

Ci sono due modi in cui questo potrebbe andare storto. In primo luogo, se stai eseguendo il casting tra due tipi in gerarchie di ereditarietà completamente diverse, il compilatore saprà che sei sciocco e ti fermerà:

String o = "str";
Integer str = (Integer)o; //Compilation fails here

In secondo luogo, se si trovano nella stessa gerarchia ma sono ancora un cast non valido, ClassCastExceptionverrà lanciato un a runtime:

Number o = new Integer(5);
Double n = (Double)o; //ClassCastException thrown here

Ciò significa essenzialmente che hai violato la fiducia del compilatore. Hai detto che puoi garantire che l'oggetto è di un tipo particolare, e non lo è.

Perché hai bisogno di casting? Bene, per iniziare ne hai bisogno solo quando passi da un tipo più generale a un tipo più specifico. Ad esempio, Integereredita da Number, quindi se vuoi memorizzare un Integercome a Numberallora va bene (dato che tutti i numeri interi sono numeri). Tuttavia, se vuoi andare dall'altra parte hai bisogno di un cast - non tutti i numeri sono interi (come pure as Integer abbiamo Double, Float, Byte, Long, ecc) e anche se c'è solo una sottoclasse nel vostro progetto o il JDK, qualcuno potrebbe facilmente creare un altro e distribuire che, così hai alcuna garanzia, anche se si pensa che è un unico, scelta obbligata !

Per quanto riguarda l'uso per il casting, ne vedi ancora la necessità in alcune librerie. Prima di Java-5 è stato utilizzato pesantemente nelle raccolte e in varie altre classi, poiché tutte le raccolte hanno lavorato sull'aggiunta di oggetti e quindi sul casting del risultato che si ottiene di nuovo dalla raccolta. Tuttavia, con l'avvento dei generici gran parte dell'uso per il casting è andato via - è stato sostituito da generici che forniscono un'alternativa molto più sicura, senza il potenziale per ClassCastExceptions (infatti se usi i generici in modo pulito e si compila senza avvertimenti, hai la garanzia che non riceverai mai un'eccezione ClassCastException.)


Grazie per la tua spiegazione. Se lo capisco correttamente, probabilmente non lo so, quando esegui il cast di un oggetto stai solo dicendo al compilatore che so che l'oggetto su questo indirizzo di memoria sa come rispondere a questi metodi ecc., Quindi non negarmi? È corretto?
user626912

1
@ user626912 Tipo di - non pensarci in termini di indirizzi di memoria però. Non stai solo dicendo al compilatore che l'oggetto dato è conforme a un'interfaccia e quindi ha implementazioni di metodi dati (potresti creare un oggetto completamente diverso con gli stessi metodi e il casting non funzionerebbe necessariamente). Stai dicendo al compilatore che l'oggetto di un tipo è in realtà un tipo più specifico e quindi è possibile utilizzare i metodi disponibili su quell'oggetto più specifico. Leggi il polimorfismo se non l'hai già fatto, potrebbe aiutare a rendere più chiare alcune cose.
Michael Berry

Dubito della tua affermazione "ne hai bisogno solo quando passi da un tipo più generale a un tipo più specifico". ((Object) gpsLastLoc.getLatitude ()). GetClass (). GetSimpleName () restituirà il nome "double" nel runtime, e questo è l'uso di esempio del casting da un tipo più specifico a un tipo più generale.
Frutta

1
@ 林果 皞 In questo caso stai solo usando il casting per promuovere una primitiva - non è la stessa cosa che andare a un tipo più generale e un modo molto strano di fare le cose. Il modo più normale (migliore) sarebbe Double.valueOf(gpsLastLoc.getLatitude()).getClass().getSimpleName(). In entrambi i casi, non dovresti mai aver bisogno di ottenere dinamicamente la classe di una primitiva, poiché se getLatitude()restituisce una doppia primitiva, sai sempre che promuoverà a un Doubleoggetto.
Michael Berry

Adoro il modo in cui lo metti, che il codice ha "violato la fiducia del compilatore". (Ps. Hai un errore di battitura, hai scritto "sei" invece di "hai".)
Jason L.

7

In realtà, il casting non funziona sempre. Se l'oggetto non è una instanceofclasse a cui lo stai trasmettendo, otterrai un ClassCastExceptionin runtime.


5

Supponi di voler eseguire il cast di a Stringin a File(sì, non ha alcun senso), non puoi lanciarlo direttamente perché la Fileclasse non è una figlia e non è un genitore della Stringclasse (e il compilatore si lamenta).

Ma potresti lanciare il tuo Stringa Object, perché a Stringè un Object( Objectè genitore). Quindi potresti lanciare questo oggetto su un File, perché un file è un fileObject .

Quindi tutte le operazioni sono "legali" dal punto di vista della digitazione in fase di compilazione, ma ciò non significa che funzionerà a runtime!

File f = (File)(Object) "Stupid cast";

Il compilatore lo consentirà anche se non ha senso, ma si bloccherà in fase di esecuzione con questa eccezione:

Exception in thread "main" java.lang.ClassCastException:
    java.lang.String cannot be cast to java.io.File

3

Il cast di un riferimento funzionerà solo se è di instanceofquel tipo. Non puoi lanciare riferimenti casuali. Inoltre, è necessario leggere di piùCasting Objects .

per esempio

String string = "String";

Object object = string; // Perfectly fine since String is an Object

String newString = (String)object; // This only works because the `reference` object is pointing to a valid String object.

3

Il modo giusto è questo:

Integer i = Integer.class.cast(obj);

Il metodo cast()è un'alternativa molto più sicura al casting in fase di compilazione.

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.