Почему Java API использует int вместо short или byte?
почему Java API использует int
, когда short
или даже byte
будет достаточно?
Пример:DAY_OF_WEEK
6 ответов
некоторые из причин уже были указаны. Например, тот факт, что "...(Почти) все операции над byte, short будут продвигать эти примитивы до int". Однако очевидным следующим вопросом будет:почему эти типы повышены до int
?
Итак, чтобы пойти на один уровень глубже: ответ может быть просто связан с набором инструкций виртуальной машины Java. Как резюмируется в таблица в виртуальном Java Спецификация Машины, все интегральные арифметические операции, как сложение, деление и другие, доступны только для типа int
тип long
и не для небольших типов.
(в сторону: меньшие типы (byte
и short
) в основном предназначены только для массивы. Ан массив как new byte[1000]
займет 1000 байт, и массив, как new int[1000]
примет 4000 байт)
теперь, конечно, можно сказать, что "...следующий очевидный вопрос:--23-->почему эти инструкции, предлагаются только для int
(и long
)?".
одна из причин упоминается в спецификации JVM, упомянутой выше:
если бы каждая типизированная инструкция поддерживала все типы данных времени выполнения виртуальной машины Java, было бы больше инструкций, чем может быть представлено в байт
кроме того, виртуальную машину Java можно рассматривать как абстракцию реального процессора. И представляя посвященный Арифметический Логический Блок для меньших типов не стоило бы усилий: ему понадобились бы дополнительные транзисторы, но он все равно мог бы выполнить только одно дополнение в одном такте. Доминирующая архитектура при разработке JVM была 32bits, как раз для 32bit int
. (Операции, которые включают 64bit long
значение реализуются как частный случай).
(Примечание: последний абзац немного упрощен, учитывая возможную векторизацию и т. д., но должен дать основную идею, не погружаясь слишком глубоко в темы дизайна процессора)
EDIT: короткое добавление, сосредоточенное на примере вопроса, но в более общем смысле: можно также спросить, не было бы полезно хранить поля использование меньших типов. Для например, можно подумать, что память можно сохранить, сохранив Calendar.DAY_OF_WEEK
как byte
. Но здесь в игру вступает формат файла класса Java: все поля в файле класса занимают по крайней мере один "слот", которая имеет размер один int
(32 бита). ("Широкие" поля,double
и long
, занимают два слота). Таким образом, явное объявление поля как short
или byte
также не сохранит память.
(почти) все операции на byte
, short
будет способствовать их int
, например, вы не можете написать:
short x = 1;
short y = 2;
short z = x + y; //error
арифметика проще и проще при использовании int
, нет необходимости, чтобы бросить.
С точки зрения пространства, это делает очень небольшая разница. byte
и short
усложнило бы вещи, я не думаю, что эта микро-оптимизация стоит того, так как мы говорим о фиксированной сумме переменная.
byte
актуально и полезно, когда вы программируете для встроенных устройств или имеете дело с файлами/сетями. Также эти примитивы ограничены, что, если расчеты могут превысить их пределы в будущем? Попробуйте подумать о расширении для Calendar
класс, который может развиваться большими числами.
также обратите внимание, что в 64-битных процессорах местные жители будут сохранены в регистрах и не будут использовать никаких ресурсов, поэтому используйте int
, short
и другие примитивы не не имеет никакого значения. Кроме того, многие реализации Java выравнивают переменные* (и объекты).
*byte
и short
занимают то же место, что и int
если они местные переменные класс переменные или даже экземпляр переменные. Почему? Потому что в (большинстве) компьютерных систем адреса переменных соответствие, например, если вы используете один байт, вы фактически в итоге два байта - один для самой переменной, а другой для заполнения.
С другой стороны, в массивах, byte
взять 1 байт short
принимаем 2 байта и int
возьмите четыре байта, потому что в массивах только начало и, возможно, конец его должен быть выровнен. Это будет иметь значение, если вы хотите использовать, например,System.arraycopy()
, тогда вы действительно заметите разницу в производительности.
потому что арифметические операции проще при использовании целых чисел по сравнению с шортами. Предположим, что константы действительно были смоделированы short
значения. Тогда вам придется использовать API следующим образом:
short month = Calendar.JUNE;
month = month + (short) 1; // is july
обратите внимание на явное приведение. Короткие значения неявно повышаются до int
значения, когда они используются в арифметических операциях. (В стеке операндов шорты даже выражаются как ints.) Это было бы довольно громоздко использовать, поэтому int
значения часто предпочитаемый для констант.
по сравнению с этим, выигрыш в эффективности хранения минимален, потому что существует только фиксированное число таких констант. Речь идет о 40 константах. Изменение их хранения с int
to short
будет безопасно для вас 40 * 16 bit = 80 byte
. См.ответ для дальнейшего использования.
Если вы использовали философию, в которой интегральные константы хранятся в наименьшем типе, в который они вписываются, тогда Java будет иметь серьезную проблему: всякий раз, когда программисты пишут код с использованием интегральных констант, они должны обратить пристальное внимание на свой код, чтобы проверить, имеет ли значение тип констант, и если да, то найдите тип в документации и/или сделайте любые преобразования типов.
Итак, теперь, когда мы наметили серьезную проблему, Какие преимущества вы могли бы надеяться достичь с этой философией? Я не удивлюсь, если только runtime-наблюдаемый эффект этого изменения будет тем, какой тип вы получите, когда будете искать константу через отражение. (и, конечно же, какие бы ошибки ни вводили ленивые / невольные программисты, неправильно учитывающие типы констант)
взвешивание плюсов и минусов очень легко: это плохая философия.
сложность проектирования виртуальной машины зависит от того, сколько видов операций она может выполнять. Проще иметь четыре реализации инструкции типа "multiply" -по одной для 32-разрядного целого, 64-разрядного целого, 32-разрядной плавающей точки и 64-разрядной плавающей точки-чем иметь, в дополнение к вышеизложенному, версии для меньших числовых типов. Более интересный вопрос дизайна-почему должно быть четыре типа, а не меньше (выполнение всего целого числа вычисления с 64-разрядными целыми числами и / или выполнение всех вычислений с плавающей запятой с 64-разрядными значениями с плавающей запятой). Причина использования 32-разрядных целых чисел заключается в том, что Java, как ожидается, будет работать на многих платформах, где 32-разрядные типы могут действовать так же быстро, как 16-разрядные или 8-разрядные типы, но операции с 64-разрядными типами будут заметно медленнее. Даже на платформах, где 16-разрядные типы будут работать быстрее, дополнительные затраты на работу с 32-разрядными величинами будут компенсированы простотой предоставлено только наличие 32-разрядных типов.
Что касается выполнения вычислений с плавающей запятой на 32-разрядных значениях, преимущества немного менее ясны. Есть некоторые платформы, где вычисление, как float a=b+c+d;
может быть выполнено наиболее быстро путем преобразования всех операндов в тип с более высокой точностью, добавления их, а затем преобразования результата обратно в 32-разрядное число с плавающей запятой для хранения. Есть и другие платформы, где было бы эффективнее выполнять все расчетов с использованием 32-разрядных значений с плавающей запятой. Создатели Java решили, что все платформы должны быть обязаны делать то же самое, и что они должны отдавать предпочтение аппаратным платформам, для которых 32-разрядные вычисления с плавающей запятой быстрее, чем более длинные, хотя это сильно ухудшило скорость и точность математики с плавающей запятой на типичном ПК, а также на многих машинах без единиц с плавающей запятой. Обратите внимание, кстати, что в зависимости от значений b, c и d, используя более высокоточные промежуточные вычисления при вычислении выражений, таких как вышеупомянутые float a=b+c+d;
иногда будут давать результаты, которые значительно более точны, чем были бы достигнуты для всех промежуточных операндов, вычисленных при float
точность, но иногда будет давать значение, которое немного менее точно. В любом случае, Sun решила, что все должно быть сделано так же, и они решили использовать минимальную точность float
значения.
обратите внимание, что основной преимущества меньших типов данных становятся очевидными, когда большое их количество хранится вместе в массиве; даже если не было никакого преимущества в том, что отдельные переменные типов меньше 64-бит, стоит иметь массивы, которые могут хранить меньшие значения более компактно; наличие локальной переменной byte
, а не long
сохраняет семь байтов; имея массив из 1,000,000 чисел, держите каждое число как byte
, а не long
волны 7,000,000 байт. Поскольку каждый тип массива нужно только поддерживать несколько операций (в частности, читать один элемент, хранить один элемент, копировать диапазон элементов в массиве или копировать диапазон элементов из одного массива в другой), дополнительная сложность наличия большего количества типов массивов не так серьезна, как сложность наличия большего количества типов непосредственно используемых дискретных числовых значений.
на самом деле, это было бы небольшое преимущество. Если у вас есть
class MyTimeAndDayOfWeek {
byte dayOfWeek;
byte hour;
byte minute;
byte second;
}
тогда на типичном JVM ему нужно столько же места, сколько и классу, содержащему один int
. Потребление памяти округляется до следующего кратного 8 или 16 байтов (IIRC, который настраивается), поэтому случаи, когда есть реальное сохранение, довольно редки.
этот класс будет немного проще в использовании, если соответствующие Calendar
методы возвратил byte
. Но таких нет!--3--> методы, только get(int)
, который должен возвращает int
из-за других полей. Каждая операция на меньших типах способствует int
, поэтому вам нужно много кастинга.
скорее всего, вы либо сдадитесь и переключитесь на int
или написать сеттеры, как
void setDayOfWeek(int dayOfWeek) {
this.dayOfWeek = checkedCastToByte(dayOfWeek);
}
потом типа DAY_OF_WEEK
не имеет значения, в любом случае.