Нам потрібно розрізнити два аспекти констант:
- назви значень, відомих на час розробки, які ми вводимо для кращої ремонтопридатності, і
- значення, доступні компілятору.
І тут є пов'язаний третій вид: змінні, значення яких не змінюється, тобто імена для значення. Різниця між цими незмінними змінними та константою полягає в тому, коли значення визначається / призначається / ініціалізується: змінна ініціалізується під час виконання, але значення константи відоме під час розробки. Ця відмінність трохи каламутна, оскільки значення може бути відоме під час розробки, але насправді створюється лише під час ініціалізації.
Але якщо значення константи відоме під час компіляції, тоді компілятор може виконувати обчислення з цим значенням. Наприклад, мова 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/"
хоча, можливо, деякі або всі з них повинні бути вказані у файлах конфігурації, а не в коді.