Почему явное приведение типов требуется от 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 делает эти типы по крайней мере несколько терпимыми.

Другие вопросы по тегам