Aby uzyskać rozsądną implementację języka Java:
Każdy obiekt ma nagłówek zawierający między innymi wskaźnik do typu środowiska wykonawczego (na przykład Doublelub String, ale nigdy nie może to być CharSequencelub AbstractList). Zakładając, że kompilator środowiska uruchomieniowego (ogólnie HotSpot w przypadku Sun'a) nie może statycznie określić typu, a wygenerowany kod maszynowy musi przeprowadzić pewne sprawdzenia.
Najpierw należy odczytać wskaźnik do typu środowiska wykonawczego. Jest to i tak konieczne do wywołania metody wirtualnej w podobnej sytuacji.
W przypadku rzutowania na typ klasy wiadomo dokładnie, ile jest superklas, dopóki nie trafisz java.lang.Object, więc typ można odczytać ze stałym przesunięciem od wskaźnika typu (właściwie pierwsza osiem w HotSpot). Ponownie jest to analogiczne do odczytu wskaźnika metody dla metody wirtualnej.
Wtedy odczytana wartość wymaga porównania z oczekiwanym statycznym typem rzutowania. W zależności od architektury zestawu instrukcji, inna instrukcja będzie musiała rozgałęzić się (lub spowodować błąd) w nieprawidłowej gałęzi. ISA, takie jak 32-bitowe ARM, mają instrukcje warunkowe i mogą mieć możliwość przejścia smutnej ścieżki przez szczęśliwą ścieżkę.
Interfejsy są trudniejsze z powodu wielokrotnego dziedziczenia interfejsu. Zwykle ostatnie dwa rzuty do interfejsów są buforowane w typie środowiska uruchomieniowego. W bardzo wczesnych dniach (ponad dziesięć lat temu) interfejsy były nieco powolne, ale to już nie ma znaczenia.
Miejmy nadzieję, że widzisz, że tego rodzaju rzeczy są w dużej mierze nieistotne dla wydajności. Twój kod źródłowy jest ważniejszy. Jeśli chodzi o wydajność, największym hitem w twoim scenariuszu mogą być chybienia w pamięci podręcznej spowodowane ściganiem wskaźników obiektów w całym miejscu (informacje o typie będą oczywiście powszechne).