Какова стоимость кастинга на Java? Это хорошая идея, чтобы избежать этого?

Я знаю, что есть два типа кастинга, которые являются неявным и явным отливом. Я прочитал разные вопросы о StackOverflow, такие как this, this и это, но мне все еще интересно, какова стоимость кастинга на Java, и это хорошая идея избежать этого? Какая для этого лучшая практика?

Существует 2 типа кастинга:

String s = "Cast";
Object o = s; // implicit casting

Object o = someObject;
String s = (String) o; // explicit casting

В этом втором случае во время выполнения есть накладные расходы, потому что два типа должны быть проверены, и в случае, если кастинг невозможен, JVM должен выбросить ClassCastException.

Кто-то сказал, что лучше профилировать приложение, чтобы убедиться, что кастинг полезен или нет.

Ответ 1

Приведение типов обычно является показателем того, что вы должны подумать об альтернативном решении вашей проблемы. В конце концов, все, что можно проверить во время компиляции, поможет программисту.

Однако иногда типы приведения неизбежны, а в Generic-коде часто случаются без того, что программист никогда не замечает. Поэтому были предприняты значительные усилия для того, чтобы сделать литье типа довольно быстрым.

В прошлом при запуске типа run включалась возможность того, что иерархия супертипа должна быть пройдена, чтобы найти совпадение. Сегодня приведение типов - это не что иное, как сравнение чисел и простое сравнение указателей, если они не оптимизированы, когда анализатор может доказать, что приведение всегда будет успешным.

Чтобы быстро создавать кастинг типов, каждый класс знает свою глубину в иерархии классов и имеет таблицу, содержащую все супер типы. Чтобы протестировать класс, его глубина сравнивается, и если глубина ниже, он не может быть совместимым классом, и тип cast не работает. В противном случае запись таблиц в позиции, равной глубине проверяемого класса, должна точно соответствовать, так что все они должны тестироваться.

Например:

Object o=new JButton();
Container c=(Container)o;

Класс Container имеет глубину 3 и следующую таблицу суперклассов:

Object
Component
Container

Класс JButton имеет глубину 5 и следующую таблицу суперклассов:

Object
Component
Container
JComponent
JButton

Теперь тип cast проверяет:

  • JButton имеет глубину 5, которая составляет ≥ 3, глубину Container, поэтому тест может преуспеть.
  • Третий элемент в таблицах проверяется и является точным соответствием:

    Object          Object
    Component       Component
    Container   <=> Container
    JComponent
    JButton
    

Итак, иерархия больше не пересекается, и операция литья типа довольно дешевая.

Ответ 2

В этом втором случае во время выполнения есть накладные расходы, потому что два типа должны быть проверены, и в случае, если кастинг невозможен, JVM должен выбросить исключение ClassCastException.

Не обязательно, очень вероятно, что для простого случая, подобного этому, JIT сможет выяснить, что бросок всегда будет работать и будет оптимизировать проверку. Выполнение микрофункции подтверждает предположение:

Benchmark                  Mode  Samples  Score   Error  Units
c.a.p.SO26335959.cast      avgt        5  3.177 ± 0.060  ns/op
c.a.p.SO26335959.noCast    avgt        5  3.174 ± 0.108  ns/op

В более сложных ситуациях прогнозирование ветвлений будет работать и в вашу пользу.

Нижняя строка, как обычно: измеряйте, не угадайте!

Ответ 3

Если вы не пишете критический цикл производительности для сервера, тогда вы не должны думать о том, что быстрее. Подумайте вместо того, что делает чистый, поддерживаемый код. И кастинг почти всегда находится в напряжении с этими целями и обычно может быть устранен с помощью лучшей структуры кода.

Чтобы ответить на ваши вопросы. Обычно кастинг обычно стоит практически ничего (при изменении ссылочного типа на родительский класс объекта). Знания ссылочного типа достаточно, чтобы решить, действительно ли воссоздание верен, он просто получает загрузчик классов для поиска карты наследования. Это также проверка, которая может быть выполнена во время компиляции. (Если ссылочный тип уже был запущен).

Литье вниз медленнее, так как JVM должен взять ссылку, посмотреть фактический класс объекта, который может иметь много типов (реализовать множество интерфейсов), и для каждого такого интерфейса он проверяет, допустимый тип (более или менее) для каждого из (возможно, многих) ссылочных типов. Поскольку down casting ссылается на фактический объект, его можно проверить только во время выполнения.

Вниз кастинг обычно не является проблемой производительности (и, вероятно, зависит от JVM), но я считаю, что это возможно сделать с помощью патологического выбора структуры наследования. Особенно на языках, допускающих множественное наследование.

Вы можете найти эту ссылку интересную

Ответ 4

Избегайте приведения, если это возможно. Отлитый материал сложнее поддерживать и, следовательно, имеет более высокую стоимость - если вам нужно проверить объект, используйте "instanceof" (например:

if (o instanceof String) {
   // do something
}

JVM использует это, чтобы проверить, является ли ваш объект строкой и вернет true, потому что вы устанавливаете o = s).

Если вы измените суперкласс класса позже в своем коде, отбрасывание может перестать работать, и вам нужно переработать код, а за ним вы можете просто изменить класс, который должен быть проверен.

//Пожалуйста, поправьте меня, если я ошибаюсь.

О стоимости кастования по времени: как я упоминал ранее, это будет стоить много времени, если вы измените свой код или замените суперклассы позже. Runtime-мудрый, поскольку кастинг выполняется, потому что нет безопасности типа, для проверки требуется меньше времени выполнения, а затем он стоит за исключение из-за непредвиденной попытки броска.

Ответ 5

Сгенерированный байт-код содержит команду checkcast. Так что да, кастинг стоит чего-то. Хотя это не дорого и, скорее всего, он будет оптимизирован JIT во время выполнения.