Trước hết, chúng ta chỉ nói về các biến cục bộ . Hiệu quả cuối cùng không áp dụng cho các lĩnh vực. Điều này rất quan trọng, vì ngữ nghĩa của final
các trường rất khác biệt và phải tuân theo các tối ưu hóa trình biên dịch nặng và các hứa hẹn về mô hình bộ nhớ, hãy xem $ 17,5,1 về ngữ nghĩa của các trường cuối cùng.
Ở cấp độ bề mặt final
và effectively final
các biến cục bộ thực sự giống hệt nhau. Tuy nhiên, JLS phân biệt rõ ràng giữa hai thứ thực sự có nhiều hiệu ứng trong những tình huống đặc biệt như thế này.
Tiền đề
Từ JLS§4.12.4 về final
các biến:
Một biến hằng là một final
biến kiểu nguyên thủy hoặc kiểu String được khởi tạo bằng biểu thức hằng ( §15.29 ). Việc một biến có phải là một biến hằng số hay không có thể có ý nghĩa liên quan đến việc khởi tạo lớp ( §12.4.1 ), khả năng tương thích nhị phân ( §13.1 ), khả năng truy cập lại ( §14.22 ) và phép gán xác định ( §16.1.1 ).
Vì int
là nguyên thủy, biến a
là một biến không đổi .
Hơn nữa, từ cùng một chương về effectively final
:
Một số biến nhất định không được khai báo là cuối cùng thay vào đó được coi là cuối cùng một cách hiệu quả: ...
Vì vậy, từ cách này là worded, rõ ràng là trong ví dụ khác, a
là không được coi là một biến liên tục, vì nó là không chính thức , nhưng chỉ có hiệu quả chính thức.
Hành vi
Bây giờ chúng ta đã có sự phân biệt, chúng ta hãy tìm kiếm những gì đang xảy ra và tại sao đầu ra lại khác nhau.
Bạn đang sử dụng toán tử điều kiện ? :
ở đây, vì vậy chúng tôi phải kiểm tra định nghĩa của nó. Từ JLS§15.25 :
Có ba loại biểu thức điều kiện, được phân loại theo biểu thức toán hạng thứ hai và thứ ba: biểu thức điều kiện boolean , biểu thức điều kiện số và biểu thức điều kiện tham chiếu .
Trong trường hợp này, chúng ta đang nói về một biểu thức điều kiện số , từ JLS§15.25.2 :
Loại biểu thức điều kiện số được xác định như sau:
Và đó là phần mà hai trường hợp được phân loại khác nhau.
hiệu quả cuối cùng
Phiên bản effectively final
phù hợp với quy tắc này:
Mặt khác, thăng hạng số tổng quát ( §5.6 ) được áp dụng cho toán hạng thứ hai và thứ ba, và kiểu của biểu thức điều kiện là kiểu thăng hạng của toán hạng thứ hai và thứ ba.
Đó là hành vi giống như nếu bạn sẽ làm 5 + 'd'
, tức là int + char
dẫn đến kết quả int
. Xem JLS§5.6
Quảng cáo số xác định loại quảng cáo của tất cả các biểu thức trong ngữ cảnh số. Kiểu được thăng hạng được chọn sao cho mỗi biểu thức có thể được chuyển đổi thành kiểu được thăng hạng, và trong trường hợp là phép toán số học, phép toán được xác định cho các giá trị của kiểu được thăng hạng. Thứ tự của các biểu thức trong ngữ cảnh số không có ý nghĩa đối với việc quảng bá số. Luật như sau:
[...]
Tiếp theo, chuyển đổi nguyên thủy mở rộng ( §5.1.2 ) và chuyển đổi nguyên thủy thu hẹp ( §5.1.3 ) được áp dụng cho một số biểu thức, theo các quy tắc sau:
Trong ngữ cảnh lựa chọn số, các quy tắc sau sẽ áp dụng:
Nếu bất kỳ biểu thức nào thuộc kiểu int
và không phải là một biểu thức hằng ( §15.29 ), thì kiểu được thăng cấp là int
và các biểu thức khác không thuộc kiểu sẽ int
trải qua chuyển đổi nguyên thủy mở rộng thành int
.
Vì vậy, mọi thứ được quảng bá int
như a
là một int
đã. Điều đó giải thích đầu ra của 97
.
sau cùng
Phiên bản có final
biến được khớp theo quy tắc này:
Nếu một trong các toán hạng là loại T
nơi T
là byte
, short
hoặc char
, và các toán hạng khác là một biểu thức hằng số ( §15.29 ) loại int
có giá trị được biểu diễn trong loại T
, sau đó loại các biểu thức điều kiện là T
.
Biến cuối cùng a
là kiểu int
và một biểu thức hằng số (vì nó là final
). Nó có thể đại diện được char
, do đó kết quả là loại char
. Điều đó kết thúc đầu ra a
.
Ví dụ về chuỗi
Ví dụ với đẳng thức chuỗi dựa trên sự khác biệt cốt lõi giống nhau, final
các biến được coi là biểu thức / biến hằng số, và effectively final
không phải.
Trong Java, quá trình xen chuỗi dựa trên các biểu thức hằng, do đó
"a" + "b" + "c" == "abc"
là true
tốt (không sử dụng cấu trúc này trong mã thực).
Xem JLS§3.10.5 :
Hơn nữa, một chuỗi ký tự luôn đề cập đến cùng một trường hợp của chuỗi lớp. Điều này là do các ký tự chuỗi - hoặc nói chung hơn , các chuỗi là giá trị của biểu thức hằng ( §15.29 ) - được "thực hiện" để chia sẻ các trường hợp duy nhất, bằng cách sử dụng phương thức String.intern
( §12.5 ).
Dễ bị bỏ qua vì nó chủ yếu nói về nghĩa đen, nhưng nó thực sự cũng áp dụng cho các biểu thức hằng.