final
tuyên bố tham chiếu đối tượng không thể sửa đổi, ví dụ:
private final Foo something = new Foo();
tạo mới Foo
và đặt tham chiếu trong something
.Sau đó, bạn không thể thay đổi something
để trỏ đến một trường hợp khác là Foo
.
Điều này làm không ngăn không cho sửa đổi trạng thái bên trong của đối tượng. Tôi vẫn có thể gọi bất kỳ phương thức nào trên Foo
có thể truy cập vào phạm vi có liên quan. Nếu một hoặc nhiều phương thức đó sửa đổi trạng thái bên trong của đối tượng đó, thì final
sẽ không ngăn điều đó.
Như vậy, sau đây:
private final Set<String> fixed = new HashSet<String>();
không không tạo Set
mà không thể được thêm vào hoặc thay đổi; nó chỉ có nghĩa là fixed
sẽ chỉ bao giờ tham chiếu đến trường hợp đó.
Ngược lại, thực hiện:
private Set<String> fixed = Collections.unmodifiableSet(new HashSet<String>());
tạo ra một thể hiện của một Set
mà sẽ ném UnsupportedOperationException
nếu một cố gắng gọi fixed.add()
hoặc fixed.remove()
, ví dụ - đối tượng chính nó sẽ bảo vệ nhà nước nội bộ của mình và ngăn chặn nó từ đang được sửa đổi.
Đối với đầy đủ lợi ích:
private final Set<String> fixed = Collections.unmodifiableSet(new HashSet<String>());
tạo ra một thể hiện của một Set
mà sẽ không cho phép tình trạng nội bộ của mình phải được thay đổi, và cũng có nghĩa là fixed
sẽ chỉ bao giờ trỏ đến một thể hiện của bộ đó.
Lý do có thể sử dụng final
để tạo các hằng số nguyên thủy dựa trên thực tế là không thể thay đổi giá trị. Hãy nhớ rằng fixed
ở trên chỉ là một tham chiếu - một biến chứa địa chỉ không thể thay đổi được. Vâng, đối với nguyên thủy, ví dụ:
private final int ANSWER = 42;
giá trị của ANSWER
là 42. Kể từ ANSWER
không thể thay đổi, nó sẽ chỉ bao giờ có giá trị 42.
Một ví dụ mà làm mờ tất cả các dòng sẽ là:
private final String QUESTION = "The ultimate question";
Theo các quy tắc trên, QUESTION
chứa địa chỉ của phiên bản String
đại diện cho "Câu hỏi cuối cùng" và địa chỉ đó không thể thay đổi được. Điều cần ghi nhớ ở đây là chính bản thân bạn không thể làm bất cứ điều gì với một phiên bản String
thay đổi nó và bất kỳ hoạt động nào có thể làm như vậy (chẳng hạn như replace
, substring
, v.v.) các phiên bản của String
.
Bài đăng hay. Tóm lại, _reference_ không thể thay đổi nhưng _contents_ của đối tượng * có thể *. – extraneon