Причина, по которой нужно указывать L для длинных, F, D для чисел с плавающей запятой, двойной - PullRequest
9 голосов
/ 23 сентября 2011

Несколько связанных вопросов здесь.

В соответствии с заголовком, почему это требование, если мы указываем тип переменной long или float, double?Разве компилятор не оценивает тип переменных во время компиляции?

Java рассматривает все интегральные литералы как int - это должно уменьшить удар непреднамеренной потери памяти?И все литералы с плавающей точкой как double - чтобы обеспечить высочайшую точность?

Ответы [ 3 ]

16 голосов
/ 23 сентября 2011

Когда у вас есть константа, есть тонкие различия между значениями, которые выглядят одинаково, но это не так.Кроме того, с тех пор, как был введен автобокс, вы получите совсем другой результат:

Рассмотрите, что вы получите, если умножить 0,1 на 0,1 как число с плавающей запятой или удвоить и преобразовать в число с плавающей запятой.

float a = (float) (0.1 * 0.1);
float b = 0.1f * 0.1f;
System.out.println("a= "+new BigDecimal(a));
System.out.println("b= "+new BigDecimal(b));
System.out.println("a == b is " + (a == b));

печатает

a= 0.00999999977648258209228515625
b= 0.010000000707805156707763671875
a == b is false

Теперь сравните то, что вы получите, если вы используете float или int для выполнения расчетов.

float a = 33333333f - 11111111f;
float b = 33333333 - 11111111;
System.out.println("a= "+new BigDecimal(a));
System.out.println("b= "+new BigDecimal(b));
System.out.println("a == b is " + (a == b));

отпечатки

a= 22222220
b= 22222222
a == b is false

Сравнить int и long

long a = 33333333 * 11111111; // overflows
long b = 33333333L * 11111111L;
System.out.println("a= "+new BigDecimal(a));
System.out.println("b= "+new BigDecimal(b));
System.out.println("a == b is " + (a == b));

отпечатков

a= -1846840301
b= 370370362962963
a == b is false

сравнить double с long

double a = 333333333333333333L  / 333333333L;
double b = 333333333333333333D  / 333333333D;
System.out.println("a= "+new BigDecimal(a));
System.out.println("b= "+new BigDecimal(b));
System.out.println("a == b is " + (a == b));

отпечатков

a= 1000000001
b= 1000000000.99999988079071044921875
a == b is false

В итоге можно построить ситуацию, когда использование int, long, double или float даст другой результат по сравнению с использованием другого типа.

8 голосов
/ 23 сентября 2011

Это становится важным, когда вы делаете больше, чем простое задание. Если вы берете

число с плавающей запятой х = 0,1 * 3,0;

имеет значение, если компьютер выполняет умножение с двойной точностью, а затем преобразует в одинарную точность или если сначала он преобразует числа в одинарную точность, а затем умножает.

редактирование: Не в этом явном случае 0.1 и 3.0, но если ваши числа станут достаточно сложными, вы столкнетесь с проблемами точности, которые показывают различия между float и double. Если сделать это явным для компилятора, если предполагается, что они равны double или float, позволяет избежать двусмысленности.

1 голос
/ 23 сентября 2011

Я считаю, что это просто, чтобы избежать путаницы. Как компилятор узнает, что 1.5 подразумевается как число с плавающей запятой или двойное число, если для него нет значения по умолчанию? Что касается оценки переменных, обратите внимание, что переменные! = Литералы.

Редактировать 1
Что касается некоторых комментариев, я считаю, что бывают случаи, когда вы не хотите, чтобы компилятор автоматически переводил литерал справа в тип переменной слева.

Редактировать 2
И, конечно же, есть

public void foo(int bar) {
  //...
}

public void foo(long bar) {
  //...
}

   //... some other method
   foo(20);  // which foo is called?
...