В Java есть примитивные типы для byte
, short
, int
и long
и то же самое для float
и double
. Почему необходимо, чтобы человек установил, сколько байтов должно использоваться для примитивного значения? Разве размер не может быть определен динамически в зависимости от того, насколько большим было переданное число?
Есть две причины, по которым я могу думать:
- Динамическая установка размера данных будет означать, что также потребуется возможность динамического изменения. Это может привести к проблемам с производительностью?
- Возможно, программист не хотел бы, чтобы кто-то мог использовать большее число, чем определенный размер, и это позволяет им ограничивать его.
Я все еще думаю, что можно было бы многого выиграть, просто используя single int
и float
type. Была ли конкретная причина, по которой Java решила не идти по этому пути?
java
language-design
data-types
numbers
yitzih
источник
источник
Ответы:
Как и многие другие аспекты языкового дизайна, речь идет о компромиссе элегантности с производительностью (не говоря уже о некотором историческом влиянии более ранних языков).
альтернативы
Конечно, возможно (и довольно просто) создать язык программирования, который имеет только один тип натуральных чисел
nat
. Почти все языки программирования, используемые для академического обучения (например, PCF, System F), имеют этот тип единого числа, который, как вы и предполагали, является более элегантным решением. Но языковой дизайн на практике - это не просто элегантность; мы также должны учитывать производительность (степень, в которой рассматривается производительность, зависит от предполагаемого применения языка). Производительность включает в себя как временные, так и пространственные ограничения.Пространство
Разрешение программисту выбрать количество байтов заранее может сэкономить место в программах с ограниченным объемом памяти. Если все ваши номера будут меньше , чем 256, то вы можете использовать 8 раз больше , чем
byte
с , какlong
с, или использовать сохраненную память для более сложных объектов. Разработчику стандартных Java-приложений не нужно беспокоиться об этих ограничениях, но они все же возникают.КПД
Даже если мы игнорируем пространство, мы все еще ограничены процессором, который имеет только инструкции, которые работают с фиксированным числом байтов (8 байтов в 64-битной архитектуре). Это означает, что даже предоставление одного 8-байтового
long
типа значительно упростит реализацию языка по сравнению с неограниченным типом натуральных чисел, поскольку можно будет отображать арифметические операции непосредственно в отдельные базовые инструкции ЦП. Если вы позволяете программисту использовать произвольно большие числа, то одна арифметическая операция должна быть сопоставлена с последовательностью сложных машинных инструкций, что приведет к замедлению работы программы. Это пункт (1), который вы подняли.Типы с плавающей точкой
Обсуждение до сих пор касалось только целых чисел. Типы с плавающей точкой - сложный зверь с чрезвычайно тонкой семантикой и крайними случаями. Таким образом, даже если мы могли бы легко заменить
int
,long
,short
иbyte
с помощью одногоnat
типа, то не ясно , что тип чисел с плавающей точкой , даже есть . Очевидно, они не являются действительными числами, поскольку действительные числа не могут существовать в языке программирования. Они также не совсем рациональные числа (хотя при желании можно создать рациональный тип). По сути, IEEE выбрал способ сортировки приближенных действительных чисел, и с тех пор все языки (и программисты) были привязаны к ним.В заключение:
Это не веская причина. Во-первых, я не могу представить себе каких-либо ситуаций, в которых типы могли бы естественно кодировать числовые границы, не говоря уже о том, что астрономически малы шансы, что границы, которые программист хочет установить, будут точно соответствовать размерам любого из примитивных типов.
источник
type my_type = int (7, 2343)
?Причина очень проста: эффективность . Несколькими способами.
Собственные типы данных. Чем ближе типы данных языка соответствуют базовым типам данных аппаратного обеспечения, тем более эффективным считается язык. (Не в том смысле, что ваши программы обязательно будут эффективными, но в том смысле, что вы можете, если действительно знаете, что делаете, писать код, который будет работать с такой же эффективностью, с какой аппаратное обеспечение может его выполнять.) Предлагаемые типы данных по Java соответствуют байты, слова, двойные слова и четырехсловые слова самого популярного оборудования. Это самый эффективный путь.
Неоправданные накладные расходы в 32-разрядных системах: если бы было принято решение отобразить все на 64-разрядную длину фиксированного размера, это привело бы к огромным потерям для 32-разрядных архитектур, которым для выполнения 64-разрядных операций требуется значительно больше тактовых циклов. битовая операция, чем 32-битная операция.
Трата памяти: существует большое количество оборудования, которое не слишком требовательно к выравниванию памяти (например, архитектуры Intel x86 и x64), поэтому массив из 100 байтов на этом оборудовании может занимать только 100 байтов памяти. Однако, если у вас больше нет байта, и вместо этого вам нужно использовать длинный, этот же массив займет на порядок больше памяти. И байтовые массивы очень распространены.
Вычисление размеров чисел. Ваше представление о динамическом определении размера целого числа в зависимости от того, насколько большим было переданное число, слишком упрощено; нет единой точки «ввода» числа; вычисление того, насколько большим должно быть число, должно выполняться во время выполнения для каждой отдельной операции, для которой может потребоваться результат большего размера: каждый раз, когда вы увеличиваете число, каждый раз, когда вы добавляете два числа, каждый раз, когда вы умножаете два номера и т. д.
Операции над числами разных размеров. Следовательно, наличие в памяти чисел потенциально разных размеров усложнит все операции: даже для простого сравнения двух чисел среда выполнения сначала должна проверить, совпадают ли оба сравниваемых числа. размер, и если нет, измените размер меньшего, чтобы соответствовать размеру большего.
Операции, для которых требуются определенные размеры операндов. Некоторые побитовые операции основаны на целочисленных значениях определенного размера. Не имея заранее определенного конкретного размера, эти операции придется эмулировать.
Накладные расходы на полиморфизм: изменение размера числа во время выполнения по существу означает, что оно должно быть полиморфным. Это, в свою очередь, означает, что это не может быть примитив фиксированного размера, выделенный в стеке, это должен быть объект, выделенный в куче. Это ужасно неэффективно. (Перечитайте №1 выше.)
источник
Чтобы не повторять пункты, которые обсуждались в других ответах, я вместо этого попытаюсь изложить несколько точек зрения.
С точки зрения языкового дизайна
Исторические причины
Это уже обсуждалось в статье в Википедии об истории Java, а также кратко обсуждается в ответе Marco13 .
Я хотел бы отметить, что:
Причины эффективности
Когда важна эффективность?
Эффективность хранения (в памяти или на диске)
Эффективность исполнения (внутри процессора или между процессором и памятью)
Необходимость в языках программирования обеспечивать абстракцию для небольших целых чисел, даже если она ограничена определенным контекстом
Interoperability
char
массив размером 256. (Пример.)BitConverter
), которые помогают упаковывать и распаковывать узкие целые числа в битовые потоки и байтовые потоки.Обработка строк
Обработка формата файла
Желательность, качество программного обеспечения и ответственность программиста
Рассмотрим следующий сценарий.
Зачастую программное обеспечение, которое может безопасно масштабироваться на много порядков, должно быть разработано для этой цели с возрастающей сложностью. Это не происходит автоматически, даже если проблема целочисленного переполнения устранена. Это подходит к полному кругу, отвечающему с точки зрения языкового дизайна: часто программное обеспечение, которое отказывается выполнять работу при непреднамеренном переполнении целого числа (сгенерировав ошибку или исключение), лучше, чем программное обеспечение, которое автоматически выполняет астрономически большие операции.
Это означает точку зрения ОП,
не является правильным. Программист должен иметь возможность, а иногда и необходимость, указывать максимальную величину, которую может принимать целочисленное значение в критических частях программного обеспечения. Как указывает ответ садовника , естественные ограничения, налагаемые примитивными типами, бесполезны для этой цели; язык должен предоставлять программистам возможность объявлять величины и применять такие ограничения.
источник
Все это происходит от оборудования.
Байт - это самая маленькая адресуемая единица памяти на большинстве аппаратных средств.
Каждый тип, который вы только что упомянули, состоит из нескольких байтов.
Байт 8 бит. При этом вы можете выразить 8 логических значений, но вы не можете искать только по одному за раз. Вы обращаетесь к 1, вы обращаетесь ко всем 8.
Раньше все было так просто, но потом мы перешли с 8-битной шины на 16, 32, а теперь и 64-битную шину.
Это означает, что, хотя мы все еще можем обращаться на уровне байтов, мы больше не можем извлечь один байт из памяти без получения соседних байтов.
Столкнувшись с этим оборудованием, разработчики языка решили позволить нам выбирать типы, которые позволяли нам выбирать типы, которые соответствуют оборудованию.
Вы можете утверждать, что такую деталь можно и нужно абстрагировать, особенно на языке, предназначенном для работы на любом оборудовании. Это может иметь скрытые проблемы с производительностью, но вы можете быть правы. Такого просто не было.
Java на самом деле пытается это сделать. Байты автоматически повышаются до Ints. Факт, который смутил вас с первого раза, когда вы попытаетесь выполнить в нем какую-то серьезную работу.
Так почему же это не сработало?
Явная большая распродажа Java в то время, когда вы могли бы использовать известный хороший алгоритм C, набрать его в Java, и с небольшими изменениями это сработало бы. И С очень близок к оборудованию.
Сохранение этого идущего и абстрагирование размера от целочисленных типов просто не работало вместе.
Чтобы они могли иметь. Они просто не
Это верное мышление. Есть способы сделать это. Функция зажима для одного. Язык может зайти так далеко, чтобы запечь произвольные границы для их типов. И когда эти границы известны во время компиляции, это позволит оптимизировать хранение этих чисел.
Ява просто не тот язык.
источник
Вероятно, одна важная причина того, почему эти типы существуют в Java, проста и печально не техническая:
C и C ++ также имели эти типы!
Хотя трудно доказать, что это является причиной, есть хотя бы некоторые веские доказательства: спецификация языка дуба (версия 0.2) содержит следующий отрывок:
Таким образом, вопрос может сводиться к:
Почему были короткие, инт, и длинные изобрели в C?
Я не уверен, является ли ответ на вопрос о письме удовлетворительным в контексте вопроса, который был задан здесь. Но в сочетании с другими ответами здесь может стать ясно, что эти типы могут быть полезны (независимо от того, является ли их существование в Java только наследием от C / C ++).
Наиболее важные причины, которые я могу придумать,
Байт - это наименьший адресуемый блок памяти (как уже упоминалось в CandiedOrange). A
byte
- это элементарный строительный блок данных, который можно прочитать из файла или по сети. Должно существовать некоторое явное представление об этом (и оно существует в большинстве языков, даже если иногда оно скрыто).Это правда, что на практике имеет смысл представлять все поля и локальные переменные, используя один тип, и вызывать этот тип
int
. С этим связан стековый поток: почему Java API использует int вместо short или byte? , Как я уже упоминал в своем ответе, одно из оправданий наличия меньших типов (byte
иshort
) состоит в том, что вы можете создавать массивы этих типов: Java имеет представление массивов, которое все еще довольно "близко к аппаратному обеспечению". В отличие от других языков (и в отличие от массивов объектов, таких какInteger[n]
массив),int[n]
массив не является коллекцией ссылок, значения которых разбросаны по всей куче. Вместо этого это будетна практике это последовательный блокn*4
байтов - один кусок памяти с известным размером и разметкой данных. Если у вас есть выбор сохранения 1000 байтов в коллекции объектов целочисленных значений произвольного размера или вbyte[1000]
(который занимает 1000 байтов), последний действительно может сэкономить некоторую память. (Некоторые другие преимущества этого могут быть более тонкими и становятся очевидными только при взаимодействии Java с нативными библиотеками)Что касается вопросов, о которых вы конкретно спрашивали:
Вероятно, было бы возможно динамически установить размер переменных, если задуматься о разработке совершенно нового языка программирования с нуля. Я не эксперт в построении компиляторов, но думаю, что было бы трудно разумно управлять коллекциями динамически изменяемых типов - особенно когда у вас строго типизированный язык. Таким образом, это, вероятно, сводится к тому, что все числа хранятся в «универсальном типе данных с произвольной точностью», что, безусловно, будет влиять на производительность. Конечно, есть языки программирования, которые строго типизированы и / или предлагают числовые типы произвольного размера, но я не думаю, что существует настоящий язык программирования общего назначения, который пошел бы по этому пути.
Примечания стороны:
Возможно, вы задались вопросом о
unsigned
модификаторе, который был упомянут в спецификации Oak. На самом деле, он также содержит замечание: «unsigned
еще не реализовано; возможно, никогда не будет». , И они были правы.В дополнение к удивлению, почему в C / C ++ вообще есть эти разные целочисленные типы, вы можете удивиться, почему они испортили их так ужасно, что вы никогда не знаете, сколько бит
int
имеет. Обоснования этого обычно связаны с производительностью и могут быть найдены в другом месте.источник
Это, безусловно, показывает, что вы еще не учили о производительности и архитектуре.
Игнорирование важности размера данных всегда влияет на производительность, вы должны использовать столько ресурсов, сколько необходимо, но не больше, всегда!
В этом заключается разница между программой или системой, которая делает действительно простые вещи и является невероятно неэффективной, требующей большого количества ресурсов и делающей использование этой системы действительно дорогостоящим; или система, которая делает много, но работает быстрее, чем другие, и действительно дешевая в эксплуатации.
источник
Есть несколько веских причин
(1) в то время как хранение однобайтовых переменных в одной длинной незначительно, хранение миллионов в массиве очень важно.
(2) «аппаратная» арифметика, основанная на конкретных целочисленных размерах, может быть намного более эффективной, и для некоторых алгоритмов на некоторых платформах это может быть важно.
источник