Ответ 1
Производительность кастинга зависит от реализации JVM.
JLS 5.5 определяет только требования к кастингу (включая рекурсивный алгоритм), но не устанавливает никаких требований к реализации. Фактически правила правил выполнения в 5.5.3 также определяются одинаково. Все реализации JVM, которые дают тот же результат, что и предлагаемый алгоритм, принимаются как надлежащая JVM.
Как правило, отбрасывание до C
занимает немного больше времени, так как JVM должен проверять тип среды выполнения объекта. При отбрасывании до A
у него нет причин делать одну и ту же проверку, так как B
extends A
.
Собственно, JVM не заботится о количестве методов и полей. Он сравнивает только иерархию типов, то же самое можно рассмотреть с помощью отражения (o.getClass()
)
Я сделал пример кода следующим образом: один downcast, затем upcast:
Object o = new Integer(1);
Integer i = (Integer) o;
Object o2 = i;
Скомпилированный байт-код выглядит следующим образом:
0 new java.lang.Integer [16]
3 dup
4 iconst_1 <-- 1 as a parameter to the constructor
5 invokespecial java.lang.Integer(int) [18] <-- constructor
8 astore_1 [o] <-- store in 'o'
9 aload_1 [o]
10 checkcast java.lang.Integer [16] <-- DOWNCAST CHECK, SPECIAL BYTECODE
13 astore_2 [i]
14 aload_2 [i]
15 astore_3 [o2] <-- WITH UPCAST NO CHECK
Итак, существует специальная инструкция JVM, которая проверяет элемент в верхней части стека с данным классом.
С повышением, проверка вообще отсутствует.
Размер классов (количество полей, методов, фактический размер) не имеет значения, потому что кастинг проверяет Class
(метаданные, которые на самом деле являются объектами).
Количество уровней иерархии и число, если реализованы интерфейсы (при переходе на интерфейс) имеет значение, потому что это проверенное дерево наследования/реализации.
Я был бы удивлен, если бы для этой проверки не было какого-то кеша.