Может ли значение константы меняться со временем?

На этапе разработки существуют определенные переменные, которые должны быть фиксированными в одном и том же режиме, но могут потребоваться со временем изменить. Например, boolean, чтобы сигнализировать режим отладки, поэтому мы делаем что-то в программе, которую мы обычно не хотели.

Неплохо ли этот стиль содержать эти значения в константе, т. е. final static int CONSTANT = 0 в Java? Я знаю, что постоянная остается неизменной во время выполнения, но также предполагается, что она должна быть одинаковой во время всего развития, за исключением незапланированных изменений, конечно?

Я искал похожие вопросы, но не нашел ничего, что соответствовало бы мне.

28 голосов | спросил GregT 8 Jpm1000000pmMon, 08 Jan 2018 16:52:27 +030018 2018, 16:52:27

7 ответов


6

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

Это бородавка в дизайне Java, так как это один из немногих случаев (возможно, единственный случай), где совместимость источника и двоичная совместимость не совпадают. За исключением этого случая, вы можете заменить зависимость с новой версией, совместимой с API, без необходимости перекомпиляции пользователей. Очевидно, что это чрезвычайно важно, учитывая, как обычно управляются Java-зависимостями.

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

Больше раздражает то, что сегодняшние JVM могут легко встроить все константы во время выполнения без штрафа за производительность (кроме необходимости загружать класс, определяющий константу, который, вероятно, все равно загружается), к сожалению, семантика языка датируется дней до JIT. И они не могут изменить язык, потому что тогда код, скомпилированный с предыдущими компиляторами, будет неправильным. Bugward-совместимость снова наносит удар.

Из-за этого некоторые люди советуют никогда не изменять статическое конечное значение вообще. Для библиотек, которые могут быть широко распространены и обновлены неизвестным образом в неизвестные моменты времени, это хорошая практика.

В вашем собственном коде, особенно в верхней части иерархии зависимостей, вы, вероятно, сойдете с ним. Но в этих случаях подумайте, действительно ли вам нужна постоянная публикация (или защита). Если константа является только видимостью пакета, разумно, в зависимости от ваших обстоятельств и стандартов кода, что весь пакет всегда будет перекомпилирован сразу, и проблема затем исчезнет. Если константа является частной, у вас нет проблем и ее можно изменить, когда захотите.

ответил fluffysheap 9 Jam1000000amTue, 09 Jan 2018 00:17:32 +030018 2018, 00:17:32
85

Все, что содержится в исходном коде, включая const объявленные глобальные константы, может быть изменено с новой версией вашего программного обеспечения.

Ключевые слова const (или final в Java), чтобы сообщить компилятору, что эта переменная не изменит , пока этот экземпляр программы работает . Больше ничего. Если вы хотите отправлять сообщения следующему сопровождающему, используйте комментарий в источнике, для чего они нужны.

// DO NOT CHANGE without consulting with the legal department!
// Get written consent form from them before release!
public const int LegalLimitInSeconds = ...

Это лучший способ общения с вашим будущим.

ответил nvoigt 8 Jpm1000000pmMon, 08 Jan 2018 17:05:55 +030018 2018, 17:05:55
13

Нам нужно выделить два аспекта констант:

  • для значений, известных во время разработки, которые мы вводим для лучшей ремонтопригодности, и
  • значения, доступные компилятору.

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

Но если значение константы известно во время компиляции, компилятор может выполнять вычисления с этим значением. Например, язык Java имеет понятие константных выражений . Постоянным выражением является любое выражение, которое состоит только из литералов примитивов или строк, операций с постоянными выражениями (таких как литье, сложение, конкатенация строк) и постоянных переменных. [ JLS §15.28 ] Постоянной переменной является переменная final, которая инициализируется константным выражением. [JLS §4.12.4] Итак, для Java это постоянная времени компиляции:

 public static final int X = 7;

Это становится интересным, когда постоянная переменная используется в нескольких единицах компиляции, а затем изменение объявления. Рассмотрим:

  • A.java:

     public class A { public static final int X = 7; }
    
  • B.java:

     public class B { public static final int Y = A.X + 2; }
    

Теперь, когда мы скомпилируем эти файлы, байт-код 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 для изменения! Здесь нет никакого смысла, важно помнить, что значение констант some действительно важно и не может быть просто изменено.

Но для большинства констант, изменяющих их, будет хорошо, если будут рассмотрены вышеприведенные ограничения. Постоянная безопасна для изменения, когда важно значение, а не конкретное значение. Это, например, случай для таких перегородок, как BORDER_WIDTH = 2 или TIMEOUT = 60; // seconds или шаблоны, такие как API_ENDPOINT = "https://api.example.com/v2/" - хотя возможнонекоторые или все из них должны быть указаны в файлах конфигурации, а не в коде.

ответил amon 8 Jpm1000000pmMon, 08 Jan 2018 18:27:33 +030018 2018, 18:27:33
6

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

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

Сохраняя приложение, которое включало бы рисование ограничивающих прямоугольников для фигур, чтобы мы могли отлаживать, как они были нарисованы, мы столкнулись с проблемой. После рефакторинга весь код, который был отключен флагами компилятора, не будет компилироваться. После этого мы намеренно изменили наши флаги компилятора на константы приложения.

Я говорю это, чтобы продемонстрировать, что есть компромиссы. Вес нескольких булевых элементов не заставил приложение работать из памяти или занимать слишком много места. Это может быть неверно, если ваша константа - действительно большой объект, который по существу имеет дескриптор ко всему в вашем коде. Если он не берет на себя удаление всех ссылок, которые он держит для объекта после того, как он больше не нужен, то ваш объект может быть источником утечки памяти.

  

Вам нужно оценить вариант использования и почему вы хотите изменить константы.

Я не поклонник простых заявлений, но вообще ваш старший коллега прав. Если что-то обязательно изменится часто, возможно, это должен быть настраиваемый элемент. Например, вы могли бы убедить своего коллегу в постоянном IsInDebugMode = true, когда вы хотите защитить какой-то код от нарушения. Однако некоторые вещи, возможно, придется менять чаще, чем вы отпустите приложение. Если это так, вам нужно изменить это значение в соответствующее время. Вы можете взять пример TaxRate = .065. Это может быть правдой во время компиляции вашего кода, но из-за новых законов он может измениться до того, как вы выпустите следующую версию своего приложения. Это то, что необходимо обновить либо из некоторого механизма хранения (например, файла или базы данных).

ответил Berin Loritsch 8 Jpm1000000pmMon, 08 Jan 2018 17:18:08 +030018 2018, 17:18:08
2

const, #define или final - подсказка компилятора (обратите внимание, что #define на самом деле не подсказка, ее макрос и значительно более мощный). Это указывает на то, что значение не изменится при выполнении программы, и могут быть сделаны различные оптимизации.

Однако, как подсказка компилятора, компилятор делает то, что не всегда может ожидать программист. В частности, javac будет встраивать static final int FOO = 42;, чтобы в любом месте FOO, скомпилированный байтовый код actual будет читать 42.

Это не слишком большой сюрприз, пока кто-то не изменит значение без перекомпиляции другой единицы компиляции (.java-файл) - и 42 остается в байтовом коде (см. можно ли отключить вставку javac статических конечных переменных? ).

Создание чего-то static final означает, что это так, и навсегда это будет больше, а изменение - действительно большая сделка - особенно если ее ничего, кроме private.

Константы для таких вещей, как final static int ZERO = 0, не проблема. final static double TAX_RATE = 0.55 (кроме денег, а double - плохо, и должен использовать BigDecimal, но тогда его не примитивный и, следовательно, не вложенный) является проблемы и должны быть тщательно изучены там, где они используются.

ответил user292808 8 Jpm1000000pmMon, 08 Jan 2018 18:22:08 +030018 2018, 18:22:08
1

Как следует из названия, константы не должны изменять во время выполнения , и, на мой взгляд, константы определены как не измененные в долгосрочной перспективе (вы можете посмотреть этот вопрос SO для получения дополнительной информации.

Когда дело доходит до необходимости флажков (например, для режима разработки), вместо этого вы должны использовать файл конфигурации или параметр запуска (многие IDE поддерживают настройку параметра запуска для каждой проектной базы, см. соответствующую документацию), чтобы включить этот режим - таким образом вы сохраняете гибкость в использовании такого режима, и вы не можете забыть его менять каждый раз, когда код становится продуктивным.

ответил DMuenstermann 8 Jpm1000000pmMon, 08 Jan 2018 17:05:20 +030018 2018, 17:05:20
0

Возможность изменения между прогонами является одной из наиболее важных точек определения константы в исходном коде!

Константа дает вам четко определенное и задокументированное (в некотором смысле) местоположение для изменения значения, когда вам нужно в течение всего срока службы вашего исходного кода. Это также обещание, что изменение константы в этом месте фактически изменит все вхождения в зависимости от того, что она обозначает.

В качестве неблагоприятного примера: not имеет смысл иметь константу TRUE, которая вычисляет значение ---- +: = 1 =: + ---- на языке, который на самом деле имеет true ключевое слово. Вы никогда бы, даже когда-либо, не объявляли true за исключением жестокой шутки.

Конечно, существуют и другие применения констант, например сокращение кода (TRUE=false), избегая дублирования (CO_NAME = 'My Great World Unique ACME Company'), устанавливая условные обозначения (PI=3.141) или что угодно, но имеющие Определенная позиция для change константа, безусловно, является одной из самых заметных.

ответил AnoE 9 Jpm1000000pmTue, 09 Jan 2018 16:22:41 +030018 2018, 16:22:41

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132