Почему явное приведение типов требуется от double к float, а не от int к байту?
Рассмотрим следующее утверждение:
byte by = 5; //works fine
литерал '5' имеет тип int и достаточно мал, чтобы поместиться в переменную типа byte. Компилятор выполняет здесь неявное приведение типов (от int к байту).
Теперь рассмотрим следующий сценарий:
float fl = 5.5; //compilation error
литерал '5.5' имеет тип double, также достаточно маленький, чтобы поместиться в переменную типа float. Почему нам нужно явно набрать приведение типа этого:
float fl = (float) 5.5; //works fine
Почему компилятор не выполняет приведение для нас в случае с плавающей запятой?
4 ответа
В целочисленной версии компилятор знает, что все данные в числе 5
может храниться в byte
, Информация не теряется. Это не всегда верно для значений с плавающей запятой. Например, 0.1f
не равно 0.1d
,
Теперь для приведенного вами примера десятичное значение 5,5 точно представлено в обоих float
а также double
Таким образом, вы можете утверждать, что в этом случае никакая информация не будет потеряна - но было бы довольно странно, если бы спецификация языка сделала это допустимым:
float f = 5.5;
но это неверно:
float f = 5.6;
Спецификация языка с удовольствием расскажет о том, находится ли число в пределах диапазона float
/ double
(хотя даже это не так просто, как вы могли бы ожидать), но когда дело доходит до того, может ли литерал быть точно представлен, я не думаю, что он когда-либо будет вдаваться в детали.
Ответ прост: потому что в спецификации сказано так (константы во время компиляции типа integer могут быть назначены меньшим типам, если они соответствуют).
Однако с плавающей точкой не столько определяется, подходит ли константа, сколько потеря точности, сопровождающая ее. Например, присвоение 1.23456789123 для двойного - это хорошо, а для float - нет. Не так очевидно, почему, в этом случае, по крайней мере, для некоторых программистов. Я бы определенно расценил это как сюрприз, когда некоторые константы с плавающей точкой работают, а другие - нет, и причина не столь ясна, как с целочисленными типами (где ограничения часто являются второй натурой для большинства).
Обратите внимание, что даже с двойными значениями иногда теряется информация. Вы можете сделать свои константы настолько точными, насколько захотите, но вы не всегда получите точное значение, указанное в переменной.
Согласился с Джоном, однако я хотел бы добавить, что
byte by = 5; //works fine until the number is less than 128
Это связано с тем, что один байт может содержать только от -128 до 127. Как только вы попытаетесь ввести число выше 127, вы получите ту же ошибку, что и при сохранении двойного значения в float.
byte by = 128; //compilation error
Таким образом, чтобы согласовать потерю данных конвертации, вам необходимо выполнить явное преобразование.
byte by = (byte) 128; // work fine
Возможно, наиболее существенная причина того, что Java допускает неявное сужающее преобразование литералов типа int
в short
а также byte
, но не делает этого для преобразования буквального double
значения для float
является то, что Java включает в себя float
литералы, но не допускает литералы типов byte
а также short
,
Лично мне очень не нравятся правила преобразования чисел в Java, но допускается хранение целочисленных констант в short
а также byte
делает эти типы по крайней мере несколько терпимыми.