Tại sao các chuỗi bất biến trong một số ngôn ngữ?


9

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?


2
@PJTraill Dường như không thể tránh khỏi. Chuỗi ký tự trong các ngôn ngữ khác không phải là bất biến trong C, và các đối tượng của các lớp khác trong Java không phải là bất biến.
David Richerby

2
Đây là một câu hỏi về thiết kế ngôn ngữ lập trình. Có vẻ như trên chủ đề, với tôi.
David Richerby

2
@DavidR Richby, chuỗi ký tự chuỗi là bất biến trong C (Theo thuật ngữ C90: Nếu chương trình cố gắng sửa đổi một chuỗi ký tự của một trong hai dạng, hành vi không được xác định. Một số phiên bản ban đầu chấp nhận do thiếu ngôn ngữ và nó đã bị lỗi đôi khi những gì lập trình viên mong đợi, nhưng tôi không nghĩ nó đã được hỗ trợ) Tôi nghĩ mọi người đã học được từ sai lầm trong FORTRAN sớm cho phép thay đổi nghĩa đen. Có nghĩa đen tạo ra đối tượng mới có thể thay đổi có giá trị ban đầu giống như nghĩa đen nếu không phải là một cái gì đó không chắc chắn.
AProgrammer

1
@AProgrammer Plenty đã được viết về lý do tại sao Java được thiết kế theo cách của nó: Tôi sẽ ngạc nhiên nếu không có gì có thẩm quyền về các quyết định thiết kế xung quanh lớp String. Nhưng, ngay cả khi các nhà thiết kế ngôn ngữ không bao giờ nói lý do tại sao String là bất biến, điều đó không làm cho câu hỏi lạc đề hoặc thậm chí xấu: điều đó chỉ có nghĩa là, thật không may, câu trả lời đúng duy nhất là "Chúng tôi không biết."
David Richerby

1
@DavidR Richby Sẽ tốt hơn nếu câu hỏi không liên quan đến ngôn ngữ. Điều này có thể được trả lời bằng cách trích dẫn một tuyên bố của một nhà phát triển Java; chúng tôi muốn câu trả lời giải thích các khái niệm.
Raphael

Câu trả lời:


9

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?"


7

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.


Chà, giá trị có thể thay đổi có thể được sử dụng để băm, nhưng tốt nhất bạn không nên biến đổi chúng sau đó nếu bạn dựa vào mã băm!
gnasher729

6

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).

  • chuỗi bất biến
  • thực hiện sao chép phòng thủ của bất kỳ chuỗi quan trọng bảo mật nào trước khi kiểm tra khả năng chấp nhận của nó.

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ý


1
Tôi rất vui vì ai đó đã chỉ ra điều này, bởi vì James Gosling hoàn toàn rõ ràng về quyết định thiết kế này. Java được thiết kế để bạn có thể chạy mã không tin cậy được gửi cho bạn qua mạng (ví dụ: trong trình duyệt web hoặc hộp hàng đầu kỹ thuật số). Lý do chính để làm cho các chuỗi không thay đổi là để giúp các nhà cung cấp hoặc người quản lý trang web (và những người triển khai thư viện tiêu chuẩn Java dễ dàng thực hiện các chính sách bảo mật tùy chỉnh của họ). Các chuỗi bất biến có hiệu quả đóng một vector tấn công tiềm năng theo thiết kế.
Bút danh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.