Chuỗi là một lớp bất biến trong Java. Một lớp bất biến chỉ đơn giản là một lớp mà các thể hiện của chúng không thể được sửa đổi. Tại sao ngôn ngữ lập trình Java chọn làm cho các đối tượng của Chuỗi lớp không thay đổi?
Chuỗi là một lớp bất biến trong Java. Một lớp bất biến chỉ đơn giản là một lớp mà các thể hiện của chúng không thể được sửa đổi. Tại sao ngôn ngữ lập trình Java chọn làm cho các đối tượng của Chuỗi lớp không thay đổi?
Câu trả lời:
Vấn đề này được liên kết chặt chẽ với khái niệm về ý nghĩa của một lớp. Theo các thuật ngữ hướng đối tượng nghiêm ngặt, một lớp có một bất biến liên quan: một vị từ luôn luôn đúng khi thoát khỏi phương thức (công khai) của lớp. Một khái niệm như vậy là trung tâm trong việc đảm bảo rằng quyền thừa kế được xác định rõ, chẳng hạn (đó là một phần của Nguyên tắc thay thế Liskov ).
Một trong những vấn đề nguy hiểm nhất với Java là rất khó để ngăn chặn mã máy khách phá vỡ các bất biến lớp.
Ví dụ: hãy xem xét lớp 'ZipCode' sau đây:
class ZipCode {
private String zipCode;
public ZipCode(String value){
if(!isValidZipCode(value))
throw new IllegalArgumentException();
zipCode = value;
assert(invariant());
}
public String get() { return zipCode; }
public boolean invariant() {
return isValidZipCode( zipCode );
}
}
Nếu Chuỗi không phải là bất biến, thì người dùng ZipCode có thể gọi 'nhận' và thay đổi các ký tự bất cứ lúc nào, do đó phá vỡ tính bất biến và phá hủy tính toàn vẹn khái niệm được cung cấp bởi khái niệm ZipCode.
Vì loại toàn vẹn này là điều cần thiết để đảm bảo rằng các hệ thống lớn là hợp lệ, câu trả lời cho câu hỏi của bạn thực sự cầu xin một trong những:
"Tại sao Java không hỗ trợ tương tự C ++ const, hoặc ít nhất cung cấp các phiên bản bất biến của nhiều lớp thư viện hơn?"
Những thứ như chuỗi và ngày là giá trị tự nhiên. Theo thuật ngữ C ++, chúng tôi hy vọng họ có một hàm tạo sao chép, toán tử gán và toán tử đẳng thức, nhưng chúng tôi không bao giờ mong đợi lấy địa chỉ của chúng. Do đó, chúng tôi không hy vọng chúng sẽ được phân bổ riêng lẻ trên đống. Phương pháp ảo không có ý nghĩa.
Các đối tượng miền là tài liệu tham khảo tự nhiên. Các C ++ không có hàm tạo sao chép, toán tử gán hoặc toán tử đẳng thức (chúng chỉ bằng nhau nếu giống hệt nhau). Chúng tôi có thể lấy địa chỉ của họ và chúng tôi hy vọng họ sẽ được phân bổ đống. Các phương thức nói chung là ảo.
Java không có các lớp giá trị, chỉ có các tham chiếu. Các giá trị được làm giả với các đối tượng bất biến. Điều này đúng với chuỗi, nhưng không, không may, cho ngày. Tính biến đổi của ngày Java đã gây ra các vấn đề thường xuyên và hiện không được chấp nhận. Chẳng hạn, các giá trị có thể thay đổi không thể được sử dụng làm cơ sở cho hàm băm.
Java được thiết kế để cho phép thực thi các phần phụ của mã chương trình trong các môi trường bị ràng buộc bảo mật. Cách thức thực hiện yêu cầu này là bằng cách đặt "SecurityManager" trên một luồng được cấp quyền truy cập vào các tham số của các hoạt động quan trọng nhất định (ví dụ: mở tệp) và hỏi liệu thao tác có được phép tiếp tục hay không. Nếu các chuỗi Java có thể thay đổi, một chương trình có thể phá vỡ các hạn chế đó bằng cách tạo hai luồng, một luồng thực hiện thao tác tệp mở sẽ được phép trong khi chuỗi kia đã sửa đổi chuỗi mà nó lưu tên tệp thành một chuỗi không được phép. Sau đó, có khả năng người quản lý bảo mật sẽ đọc chuỗi gốc, chấp nhận thao tác, sẽ được chuyển sang mã mở tệp, sau đó sẽ mở tệp thứ hai (không được phép).
Khả năng thứ hai sẽ làm cho tất cả các hoạt động như vậy chạy chậm hơn và có nhiều khả năng cho việc triển khai có chứa lỗi, vì vậy sử dụng các chuỗi bất biến là quyết định hợp lý nhất.
Nói chung, các đối tượng bất biến rất hữu ích vì chúng cho phép chia sẻ mà không cần tạo các bản sao phòng thủ (có thể cần thiết ngay cả trong mã không bảo mật để ngăn lỗi khi dữ liệu nguồn thay đổi), vì vậy ngay cả khi không có yêu cầu này, quyết định vẫn sẽ là một cái hợp lý