Посмотрите на эти три строки кода ниже.
float f = 1;
float g = 1.1;
float h = 1.1f;
Вторая строка имеет ошибки компиляции, в то время как другие строки не имеют ошибок компиляции. Первая строка хорошо работает без суффикса f, и третья строка работает с суффиксом f. Почему это?
Литералы с плавающей точкой в Java по умолчанию являются двойными
значениями.
JLS 3.10.2 Литералы с плавающей точкой
Литерал с плавающей точкой имеет тип
float
, если он имеет суффикс в виде буквы ASCIIF
илиf
; в противном случае его тип -double
, и он может быть дополнен суффиксом в виде буквы ASCIID
илиd
.
Вы не можете присвоить значение double
значению float
без явного сужающего преобразования. Поэтому у вас есть два варианта:
f
или F
для обозначения значения float
(float)
Примером последнего является:
double d = 1.1;
float f = (float) d; // compiles fine!
Причина, по которой это компилируется:
float f = 1;
заключается в том, что расширяющее преобразование из int
в float
может быть выполнено неявно в контексте присваивания.
JLS 5.2 Преобразование присваивания
Преобразование присваивания происходит, когда значение выражения присваивается переменной: тип выражения должен быть преобразован в тип переменной. Контексты присваивания позволяют использовать один из следующих способов:
- расширяющее примитивное преобразование (§5.1.2)
- [...]
JLS 5.1.2 Расширяющееся примитивное преобразование
Следующие 19 специфических преобразований примитивных типов называются расширяющимися примитивными преобразованиями:
int
вlong
,float
илиdouble
- [...]
Как упоминалось выше, существует также суффикс D
или d
для double
. Рассмотрим этот фрагмент для примера:
static void f(int i) {
System.out.println("(int)");
}
static void f(double d) {
System.out.println("(double)");
}
//...
f(1); // prints "(int)"
f(1D); // prints "(double)"
Существует также суффикс для длинных
литералов, это L
или l
(строчная буква). Настоятельно рекомендуется использовать прописную букву.
JLS 3.10.1 Целочисленные литералы
Целочисленный литерал имеет тип
long
, если он имеет суффикс в виде буквы ASCIIL
илиl
(ell
); в противном случае он имеет типint
. СуффиксL
является предпочтительным, поскольку буквуl
(ell
) часто трудно отличить от цифры1
(one
).
Вы присваиваете значение double
объекту переменная типа float
. 1.1
сам по себе (без прикрепленного к концу f
) предполагается компилятором как имеющий тип double
. Компилятор не любит делать неявные понижающие преобразования, потому что там есть вероятность потери точности.
Первая строка автоматически передает int в float (ok).
Вторая строка не могла преобразовать double в float из-за потери точности. Вы должны преобразовать:
float g = (float) 1.1;
Третья строка не требует преобразования.
В Java каждое число с плавающей точкой (любое число с десятичной точкой) по умолчанию имеет вид double
, который является более точным, чем float
. И по умолчанию Java не позволяет преобразовывать double
в float
из-за потери точности.
Вы все еще можете присвоить double
к float
путем приведения:
float g = (float) 1.1;