Вопрос

Есть ли накладные расходы, когда мы бросаем объекты одного типа на другую? Или компилятор просто решает все, и нет стоимости во время выполнения?

Это общие вещи, или есть разные случаи?

Например, предположим, что у нас есть массив объекта [], где каждый элемент может иметь другой тип. Но мы всегда знаем, что, скажем, элемент 0 - двойной, элемент 1 - это строка. (Я знаю, что это неправильный дизайн, но давайте просто предполагаем, что я должен был сделать это.)

Информация о типах Java по-прежнему хранится во время выполнения? Или все забыто после компиляции, и если мы сделаем (дважды) элементы [0], мы просто будем следовать указатель и интерпретировать эти 8 байтов как двойное, что бы то ни было?

Я очень неясно, насколько типы делаются в Java. Если у вас есть какие-либо рекомендации по книгам или статье, а также спасибо.

Это было полезно?

Решение

Есть 2 типа кастинга:

Скрытый Кастинг, когда вы отлиты от типа до более широкого типа, который выполняется автоматически, и нет накладных:

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

Явный Кастинг, когда вы идете от более широкого типа до более узкого. Для этого вы должны явно использовать такое литье:

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

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

Взято из Javaworld: стоимость кастинга

Кастинг Используется для преобразования между типами - между эталонными типами, в частности, для типа операции литья, в которой мы заинтересованы здесь.

Ускорение Операции (также называемые преобразованиями расширений в спецификации языка Java) Преобразуйте ссылку подкласс на ссылку на класс предка. Эта операция отливки обычно автоматическая, поскольку она всегда безопасна и может быть реализована непосредственно компилятором.

Сверху вниз Операции (также называемые сужающими преобразованиями в спецификации языка Java) Преобразуйте ссылку на класс предка на ссылку подкласс. Эта операция отливки создает накладные расходы выполнения, поскольку Java требует, чтобы актерский был проверен во время выполнения, чтобы убедиться, что это действительно. Если ссылка на объект не является экземпляром либо типов целевого типа для литого или подкласса этого типа, предпринимаемый камин не допускается и должен выбросить Java.lang.classcastexception.

Другие советы

Для разумной реализации Java:

Каждый объект имеет заголовок, содержащий среди прочего, указатель на тип выполнения (например, Double или String, но это никогда не может быть CharSequence или AbstractList). Предполагая, что компилятор времени выполнения (вообще точка доступа в случае солнца) не может определить тип статически некоторую проверку, необходимо выполнить сгенерированный машинный код.

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

Для литья в класс типа известно, сколько суперкласс, пока вы не ударите java.lang.Object, Таким образом, тип можно прочитать с постоянным смещением от указателя типа (фактически первые восемь в точке). Опять же, это аналогично чтению указателя метода для виртуального метода.

Тогда значение чтения только что требует сравнения с ожидаемым статическим типом литого типа. В зависимости от архитектуры набора инструкций, другая инструкция должна будет иметь ветку (или неисправность) на неверной ветке. ISAS, такая как 32-битная рука, условного инструкции, и может иметь возможность пройти печальный путь через счастливый путь.

Интерфейсы сложнее из-за многократного наследования интерфейса. Как правило, последние два катя к интерфейсам кэшируются во время выполнения. В первые дни (в течение десяти лет назад »интерфейсы были немного медленно, но это больше не актуальна.

Надеюсь, вы увидите, что такая вещь в основном не имеет значения для производительности. Ваш исходный код важнее. С точки зрения производительности, самый большой удар в вашем сценарии несет ответственность за пропустить кэш-память от преследования указателей объекта по всему месту (информация о типах, конечно, будет общей).

Например, предположим, что у нас есть массив объекта [], где каждый элемент может иметь другой тип. Но мы всегда знаем, что, скажем, элемент 0 - двойной, элемент 1 - это строка. (Я знаю, что это неправильный дизайн, но давайте просто предполагаем, что я должен был сделать это.)

Компилятор не отмечает типы отдельных элементов массива. Он просто проверяет, что тип каждого элемента экспрессии назначается типом элемента массива.

Информация о типах Java по-прежнему хранится во время выполнения? Или все забыто после компиляции, и если мы сделаем (дважды) элементы [0], мы просто будем следовать указатель и интерпретировать эти 8 байтов как двойное, что бы то ни было?

Некоторая информация поддерживается во время выполнения, но не статические типы отдельных элементов. Вы можете сказать это от поиска формата файла класса.

Теоретически возможно, что Compiler JIT может использовать «escape Analysis», чтобы устранить ненужные проверки типа в некоторых заданиях. Тем не менее, делать это со степенью, которую вы предлагаете, будет за пределами реалистической оптимизации. Выплата анализа типов отдельных элементов была бы слишком маленькой.

Кроме того, люди не должны писать код приложений в любом случае.

Инструкция по байтому коду для выполнения литья во время выполнения называется checkcast. Отказ Вы можете разобрать код Java, используя javap Чтобы увидеть, какие инструкции генерируются.

Для массивов Java хранит информацию во время выполнения. Большую часть времени компилятор поймает ошибки типа для вас, но есть случаи, когда вы столкнетесь с ArrayStoreException При попытке хранить объект в массиве, но тип не совпадает (а компилятор не поймал его). То Язык Java Spec. Дает следующий пример:

class Point { int x, y; }
class ColoredPoint extends Point { int color; }
class Test {
    public static void main(String[] args) {
        ColoredPoint[] cpa = new ColoredPoint[10];
        Point[] pa = cpa;
        System.out.println(pa[1] == null);
        try {
            pa[0] = new Point();
        } catch (ArrayStoreException e) {
            System.out.println(e);
        }
    }
}

Point[] pa = cpa действителен с ColoredPoint это подкласс точки, но pa[0] = new Point() не действует.

Это противостоит родовым типам, где нет информации, хранящейся во время выполнения. Вставки компилятора checkcast инструкции, где это необходимо.

Эта разница в печати для общих типов и массивов делает его часто неподходящим для смешивания массивов и универсальных типов.

Теоретически, введен накладные расходы. Однако современные JVMS умны. Каждая реализация отличается, но неразумно предположить, что может существовать реализация, которую JIT оптимизировал выездные чеки, когда он может гарантировать, что никогда не будет конфликта. Что касается того, какая специфическая JVMS предлагает это, я не мог сказать вам. Я должен признать, что я хотел бы знать специфики сами оптимизации JIT, но это для инженеров JVM для беспокойства.

Мораль этой истории - написать понятный код сначала. Если вы испытываете замедление, профиль и определите свою проблему. Шансы хороши, что это не будет связано с кастингом. Никогда не жертвуйте чистым, безопасным кодом в попытке оптимизировать его, пока вы не знаете, что вам нужно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top