Подтвердить что ты не робот

Почему стандартный тип целых литералов int вместо long?

Я запутался, почему Java integer литералы по умолчанию int вместо long. Это, по-видимому, вызывает ненужную путаницу.

Во-первых, это требует от программиста специального синтаксиса (добавьте "L" к литералам) при назначении значения long, которое превышает максимальный размер int (2147483647).

long x = 2147483647; // Compiles
long y = 2147483648; // Does not compile
long z = 2147483648L; // Compiles

Во-вторых, при использовании класса-оболочки long программист должен всегда использовать литеральную литературу long, как описано в этом вопросе SO.

Long x = 250; // Does not compile
Long y = 250L; // Compiles

В-третьих, учитывая, что неявное преобразование из int литералов в "более узкие" типы данных (short и byte) отлично работает во всех ситуациях (что я знаю), кажется, что просто сделать все целое число литературный тип long был бы очевидным решением... верно? Разве это не полностью устранит необходимость в этой нечетной системе добавления "L" к целочисленным литералам в особых случаях?

4b9b3361

Ответ 1

Это по дизайну 1 и кодируется в JLS: Спецификация языка Java.

Во-первых, обратите внимание, что это не связано с расширением поэтому (действительный) целочисленный литерал продвигается до длинного значения. Вместо этого это связано с самой спецификацией int literal:

Это ошибка времени компиляции, если шестнадцатеричный, восьмеричный или двоичный внутренний литерал не соответствует 32 битам.

Наименьшие и наибольшие подписанные 32-битные целочисленные значения: -2147483648 и 2147483647 соответственно.


1 Мне неинтересно, почему он работает таким образом, а языки, подобные С#, имеют разные правила.

Ответ 2

Скорость

У вас есть выигрыш в эффективности за счет использования только того размера, который вам нужен. Число int отлично для чисел от -2 ^ 31 до 2 ^ 31. Если вы используете long, где int будет достаточно, вы замедляете свой код. Например, этот код работает на 7.116 секунд на моей машине. Переключая его на использование int, я уменьшаю время работы до 3,74 секунды на моей машине:

public class Problem005 {

  private static boolean isDivisibleByAll(long n, long ceiling) {
    for (long i = 1; i < ceiling; i++)
      if (n % i != 0)
        return false;
    return true;
  }

  public static long findSmallestMultiple (long ceiling) {
    long number = 1;
    while (!isDivisibleByAll(number, ceiling))
      number++;
    return number;
  }

}

public class Stopwatch {
  private final long start;

  public Stopwatch() {
    start = System.currentTimeMillis();
  }

  public double elapsedTime() {
    long now = System.currentTimeMillis();
    return (now - start) / 1000.0;
  }

}

public class Main {

  public static void main(String[] args) {

    Stopwatch stopwatch005 = new Stopwatch();

    long highestMultiple = 20;
    long findSmallestMultipleOutput = findSmallestMultiple(highestMultiple);
    double findSmallestMultipleTime = stopwatch005.elapsedTime();
    System.out.println("Problem #005");
    System.out.println("============");
    System.out.print("The multiple of the numbers 1-" + highestMultiple + " is = ");
    System.out.print(findSmallestMultipleOutput);
    System.out.println(" with a time of " + findSmallestMultipleTime + " seconds.\n ");
  }   
}

Изменено для использования int:

public class Problem005 {

  private static boolean isDivisibleByAll(int n, int ceiling) {
    for (int i = 1; i < ceiling; i++)
      if (n % i != 0)
        return false;
    return true;
  }

  public static int findSmallestMultiple (int ceiling) {
    int number = 1;
    while (!isDivisibleByAll(number, ceiling))
      number++;
    return number;
  }

}

Ответ 3

Одна из возможных причин, по которой int является литералом по умолчанию, заключается в том, что использование lont может затруднить обнаружение ошибок в многопоточном приложении, как указано в JLS 17.7 Неатомная обработка двойного и длинного.

Для целей модели памяти языка программирования Java одна запись в долговременное длинное или двойное значение рассматривается как две отдельные записи: по одной на каждую 32-битную половину. Это может привести к ситуации, когда поток видит первые 32 бита 64-битного значения из одной записи, а второй 32 бита из другой записи.

Ответ 4

Я думаю, что вы правы, long сегодня станет лучшим дефолтом. Еще в 1995 году long, вероятно, слишком долго, чтобы быть стандартным.

Ответ 5

Для

Long x = 250;

Это не сработает. Java использует Autoboxing, который автоматически переходит из класса представления Object в примитивный тип. Что касается других, int - это только тип первичного номера. Длинны, по крайней мере, для того, для чего я их чаще всего использую, используются только для дат и времени. С другой стороны, целые числа используются по умолчанию для всего остального.

Если вы действительно хотите вникать в специфику, я уверен, что это будет шорох ваших jimmies больше:

float pi = 3.14; // Does not compile.
float pi = 3.14F; // Compiles

В этом случае double принимает приоритет, если задействован десятичный знак.

Ответ 6

Я думаю, что причиной того, что int-литералы являются те, которые не нужны, указывают на то, что int является нормальным целым типом. Аналогично, double является обычным типом с плавающей точкой. Кажется, идея состоит в том, чтобы ограничить количество литералов, которым требуется указание типа, по умолчанию для наиболее распространенного типа.

Ответ 7

Можно было бы требовать, чтобы язык требовал, чтобы вся целая арифметика, которая не переполнялась бы, если бы промежуточные результаты были вычислены с самым длинным интегральным типом, как если бы они были. На таком языке, если переменные, начинающиеся с L, равны 64 бит, те, у которых есть W, являются 32-битными, а те, у которых H - 16 бит, выражения типа

L1 = W1*W2;
W3 = (W1+W2) >> 1

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

W4 = W1+W2

будет оцениваться с использованием 32-разрядной математики (поскольку любое переполнение, которое произойдет, произойдет с назначением на W4, даже если промежуточный результат был оценен как 32 бита), а выражение типа

W5 = (H1*H2) >> 1

можно оценить как 32 бита, так как результат не может переполнить 32-битное значение.

Такой язык может быть весьма эффективным в большинстве сценариев, поскольку компилятору вообще не сложно определить максимальный размер целочисленного значения для каждого подвыражения. На таком языке не имеет значения, был ли числовой литерал "длинным" или "int", поскольку компилятор был бы более заинтересован в его числовом значении.

В Java, однако, числовые литералы разных размеров имеют разную семантику. Если умножить a int на константу 128, значение int должно быть не больше 16 777 215, иначе произойдет переполнение. Если умножить int на константу 128L, результат может быть сохранен только где-то, где можно принять long.