Chúng ta cần phân biệt hai khía cạnh của hằng số:
- tên cho một giá trị được biết đến tại thời điểm phát triển, mà chúng tôi giới thiệu để duy trì tốt hơn và
- các giá trị có sẵn cho trình biên dịch.
Và sau đó có một loại thứ ba liên quan: các biến có giá trị không thay đổi, tức là tên của một giá trị. Sự khác biệt giữa các biến bất biến này và hằng số là khi giá trị được xác định / gán / khởi tạo: một biến được khởi tạo trong thời gian chạy, nhưng giá trị của hằng được biết trong quá trình phát triển. Sự khác biệt này là một chút bùn vì một giá trị có thể được biết trong quá trình phát triển nhưng thực sự chỉ được tạo ra trong quá trình khởi tạo.
Nhưng nếu giá trị của hằng số được biết tại thời gian biên dịch, thì trình biên dịch có thể thực hiện tính toán với giá trị đó. Ví dụ, ngôn ngữ Java có khái niệm biểu thức hằng . Biểu thức không đổi là bất kỳ biểu thức nào chỉ bao gồm các chữ gốc của chuỗi nguyên thủy hoặc chuỗi, hoạt động trên các biểu thức không đổi (chẳng hạn như truyền, thêm, nối chuỗi) và các biến không đổi. [ JLS §15.28 ] Biến không đổi là final
biến được khởi tạo với biểu thức không đổi. [JLS §4.12.4] Vì vậy, đối với Java, đây là hằng số thời gian biên dịch:
public static final int X = 7;
Điều này trở nên thú vị khi một biến không đổi được sử dụng trong nhiều đơn vị biên dịch và sau đó khai báo được thay đổi. Xem xét:
Bây giờ khi chúng ta biên dịch các tệp này, B.class
mã byte sẽ khai báo một trường Y = 9
vì B.Y
là một biến không đổi.
Nhưng khi chúng ta thay đổi A.X
biến thành một giá trị khác (giả sử X = 0
) và chỉ biên dịch lại A.java
tệp, thì B.Y
vẫn đề cập đến giá trị cũ. Trạng thái A.X = 0, B.Y = 9
này không phù hợp với các khai báo trong mã nguồn. Chúc mừng gỡ lỗi!
Điều này không có nghĩa là hằng số không bao giờ được thay đổi. Các hằng số rõ ràng tốt hơn các số ma thuật xuất hiện mà không cần giải thích trong mã nguồn. Tuy nhiên, các giá trị của các hằng số công cộng là một phần của API công cộng của bạn . Điều này không đặc trưng cho Java, nhưng cũng xảy ra trong C ++ và các ngôn ngữ khác có các đơn vị biên dịch riêng biệt. Nếu bạn thay đổi các giá trị này, bạn sẽ cần biên dịch lại tất cả các mã phụ thuộc, tức là thực hiện biên dịch sạch.
Tùy thuộc vào bản chất của các hằng số, chúng có thể đã dẫn đến các giả định không chính xác của các nhà phát triển. Nếu những giá trị này bị thay đổi, chúng có thể gây ra lỗi. Ví dụ, một tập các hằng số có thể được chọn để chúng tạo thành các mẫu bit nhất định, ví dụ public static final int R = 4, W = 2, X = 1
. Nếu những điều này được thay đổi để tạo thành một cấu trúc khác như R = 0, W = 1, X = 2
mã hiện có, chẳng hạn như boolean canRead = perms & R
trở thành không chính xác. Và chỉ cần nghĩ về những niềm vui sẽ xảy ra là Integer.MAX_VALUE
thay đổi! Không có sửa chữa ở đây, điều quan trọng cần nhớ là giá trị của một số hằng thực sự quan trọng và không thể thay đổi một cách đơn giản.
Nhưng đối với phần lớn các hằng số thay đổi chúng sẽ ổn miễn là các hạn chế trên được xem xét. Một hằng số là an toàn để thay đổi khi ý nghĩa, không phải giá trị cụ thể là quan trọng. Đây là ví dụ cho trường hợp điều chỉnh như BORDER_WIDTH = 2
hoặc TIMEOUT = 60; // seconds
hoặc các mẫu như API_ENDPOINT = "https://api.example.com/v2/"
- mặc dù có thể cho rằng một số hoặc tất cả những thứ đó phải được chỉ định trong tệp cấu hình thay vì mã.