Нам нужно выделить два аспекта констант:
- имена для значений, известных во время разработки, которые мы вводим для лучшей ремонтопригодности, и
- значения, доступные для компилятора.
И затем есть связанный третий тип: переменные, значение которых не изменяется, то есть имена для значения. Разница между этими неизменяемыми переменными и константой заключается в том, что значение определяется / присваивается / инициализируется: переменная инициализируется во время выполнения, но значение константы известно во время разработки. Это различие немного мутное, так как значение может быть известно во время разработки, но фактически создается только во время инициализации.
Но если значение константы известно во время компиляции, то компилятор может выполнять вычисления с этим значением. Например, язык Java имеет концепцию константных выражений . Константное выражение - это любое выражение, состоящее только из литералов примитивов или строк, операций с константными выражениями (таких как приведение, сложение, конкатенация строк) и константных переменных. [ JLS §15.28 ] Постоянная переменная - это final
переменная, которая инициализируется постоянным выражением. [JLS §4.12.4] Итак, для Java это константа времени компиляции:
public static final int X = 7;
Это становится интересным, когда постоянная переменная используется в нескольких единицах компиляции, а затем объявление изменяется. Рассмотреть возможность:
Теперь, когда мы скомпилируем эти файлы, B.class
байт-код объявит поле, Y = 9
потому что B.Y
это постоянная переменная.
Но когда мы A.X
изменяем переменную на другое значение (скажем, X = 0
) и перекомпилируем только A.java
файл, тогда B.Y
все равно ссылается на старое значение. Это состояние A.X = 0, B.Y = 9
несовместимо с объявлениями в исходном коде. Удачной отладки!
Это не значит, что константы никогда не должны изменяться. Константы определенно лучше магических чисел, которые появляются без объяснения в исходном коде. Тем не менее, значение общественных констант является частью вашего общественного API . Это не относится к Java, но также встречается в C ++ и других языках, которые имеют отдельные модули компиляции. Если вы измените эти значения, вам нужно будет перекомпилировать весь зависимый код, т.е. выполнить чистую компиляцию.
В зависимости от природы констант, они могли привести к неверным предположениям разработчиков. Если эти значения изменены, они могут вызвать ошибку. Например, набор констант может быть выбран так, чтобы они формировали определенные битовые комбинации, например public static final int R = 4, W = 2, X = 1
. Если они изменены, чтобы сформировать другую структуру, как R = 0, W = 1, X = 2
тогда, существующий код, такой как, boolean canRead = perms & R
становится неправильным. И просто подумайте о том, что веселье должно было Integer.MAX_VALUE
измениться! Здесь нет никакого исправления, просто важно помнить, что значение некоторых констант действительно важно и не может быть изменено просто.
Но для большинства констант их изменение будет нормальным, если учесть вышеупомянутые ограничения. Константу безопасно менять, когда важно значение, а не конкретное значение. Это, например, относится к настраиваемым элементам, таким как BORDER_WIDTH = 2
или, TIMEOUT = 60; // seconds
или шаблонам, таким как, API_ENDPOINT = "https://api.example.com/v2/"
хотя, возможно, некоторые или все из них должны быть указаны в файлах конфигурации, а не в коде.