Tôi hiểu rằng trình biên dịch cần biết biểu thức tại thời điểm biên dịch để biên dịch một chuyển đổi, nhưng tại sao Foo.BA_ không đổi?
Mặc dù chúng là hằng số theo quan điểm của bất kỳ mã nào thực thi sau khi các trường đã được khởi tạo, chúng không phải là hằng số thời gian biên dịch theo nghĩa được yêu cầu bởi JLS; xem §15.28 Biểu thức hằng cho đặc điểm kỹ thuật của biểu thức hằng 1 . Điều này đề cập đến §4.12.4 Biến cuối cùng xác định "biến không đổi" như sau:
Chúng tôi gọi một biến, kiểu nguyên thủy hoặc kiểu chuỗi, là cuối cùng và được khởi tạo với biểu thức hằng số thời gian biên dịch (§15.28) là biến không đổi. Việc một biến có phải là biến không đổi hay không có thể có ý nghĩa đối với việc khởi tạo lớp (§12.4.1), khả năng tương thích nhị phân (§13.1, §13.4.9) và gán xác định (§16).
Trong ví dụ của bạn, các biến Foo.BA * không có bộ khởi tạo và do đó không đủ điều kiện là "biến không đổi". Cách khắc phục rất đơn giản; thay đổi khai báo biến Foo.BA * để có các khởi tạo là các biểu thức hằng số thời gian biên dịch.
Trong các ví dụ khác (trong đó các bộ khởi tạo đã là các biểu thức hằng số thời gian biên dịch), việc khai báo biến là final
có thể là điều cần thiết.
Bạn có thể thay đổi mã của mình để sử dụng enum
thay vì int
hằng số, nhưng điều đó mang đến một vài hạn chế khác nhau:
1 - Các hạn chế biểu thức không đổi có thể được tóm tắt như sau. Các biểu thức hằng a) có thể sử dụng các kiểu nguyên thủy và String
chỉ, b) cho phép các nguyên hàm là các chữ (ngoài null
) và các biến không đổi, c) cho phép các biểu thức không đổi có thể được ngoặc đơn như là các biểu thức con, d) cho phép các toán tử trừ các toán tử gán ++
, --
hoặc instanceof
, và e) cho phép các kiểu phôi thành các kiểu nguyên thủy hoặc String
chỉ.
Lưu ý rằng điều này không bao gồm bất kỳ hình thức gọi hoặc phương thức lambda nào new
, .class
. .length
hoặc đăng ký mảng. Hơn nữa, bất kỳ việc sử dụng các giá trị mảng, enum
giá trị, giá trị của các loại trình bao bọc nguyên thủy, quyền anh và unboxing đều bị loại trừ vì a).