Per un'implementazione ragionevole di Java:
Ogni oggetto ha un'intestazione contenente, tra le altre cose, un puntatore al tipo di runtime (ad esempio Double
o String
, ma non potrebbe mai essere CharSequence
o AbstractList
). Supponendo che il compilatore runtime (generalmente HotSpot nel caso di Sun) non sia in grado di determinare il tipo staticamente, è necessario eseguire alcuni controlli dal codice macchina generato.
Per prima cosa è necessario leggere quel puntatore al tipo di runtime. Ciò è comunque necessario per chiamare un metodo virtuale in una situazione simile.
Per eseguire il casting su un tipo di classe, è noto esattamente quante superclassi ci sono fino a quando non si preme java.lang.Object
, quindi il tipo può essere letto con un offset costante dal puntatore del tipo (in realtà i primi otto in HotSpot). Anche in questo caso è analogo alla lettura di un puntatore a un metodo per un metodo virtuale.
Quindi il valore letto necessita solo di un confronto con il tipo statico previsto del cast. A seconda dell'architettura del set di istruzioni, un'altra istruzione dovrà diramarsi (o generare un errore) su un ramo errato. ISA come ARM a 32 bit hanno istruzioni condizionali e possono essere in grado di far passare il percorso triste attraverso il percorso felice.
Le interfacce sono più difficili a causa dell'ereditarietà multipla dell'interfaccia. In genere, gli ultimi due cast alle interfacce vengono memorizzati nella cache nel tipo di runtime. All'inizio (oltre un decennio fa), le interfacce erano un po 'lente, ma questo non è più rilevante.
Si spera che tu possa vedere che questo genere di cose è in gran parte irrilevante per le prestazioni. Il tuo codice sorgente è più importante. In termini di prestazioni, il più grande successo nel tuo scenario è suscettibile di mancare nella cache dall'inseguimento di puntatori a oggetti ovunque (le informazioni sul tipo saranno ovviamente comuni).