Bất biến có nghĩa là gì?


103

Nếu một chuỗi là bất biến, điều đó có nghĩa là .... (giả sử JavaScript)

var str = 'foo';

alert(str.substr(1)); // oo

alert(str); // foo

Có nghĩa là, khi gọi các phương thức trên một chuỗi, nó sẽ trả về chuỗi đã sửa đổi, nhưng nó sẽ không thay đổi chuỗi ban đầu?

Nếu chuỗi có thể thay đổi, điều đó có nghĩa là chuỗi thứ 2 alert()cũng sẽ trả về oo?

Câu trả lời:


104

Nó có nghĩa là một khi bạn khởi tạo đối tượng, bạn không thể thay đổi các thuộc tính của nó. Trong cảnh báo đầu tiên, bạn sẽ không thay đổi foo. Bạn đang tạo một chuỗi mới. Đây là lý do tại sao trong cảnh báo thứ hai, nó sẽ hiển thị "foo" thay vì oo.

Có nghĩa là, khi gọi các phương thức trên một chuỗi, nó sẽ trả về chuỗi đã sửa đổi, nhưng nó sẽ không thay đổi chuỗi ban đầu?

Đúng. Không có gì có thể thay đổi chuỗi sau khi nó được tạo. Bây giờ, điều này không có nghĩa là bạn không thể gán một đối tượng chuỗi mới cho strbiến. Bạn chỉ không thể thay đổi đối tượng hiện tại mà str tham chiếu.

Nếu chuỗi có thể thay đổi, điều đó có nghĩa là cảnh báo thứ 2 () cũng sẽ trả về oo?

Về mặt kỹ thuật, không, vì phương thức chuỗi con trả về một chuỗi mới. Tạo một đối tượng có thể thay đổi, sẽ không thay đổi phương thức. Làm cho nó có thể thay đổi có nghĩa là về mặt kỹ thuật, bạn có thể làm cho nó để chuỗi con thay đổi chuỗi ban đầu thay vì tạo một chuỗi mới.


Chuỗi tương tự nếu được sửa đổi và gán, sẽ cập nhật chuỗi var str = 'foo'; str = str.substr (1)); // oo alert (str); // oo
Ashwin G

Điều gì về mã dưới đây. Giá trị chuỗi được thay đổi ngay bây giờ. var name = "Santosh"; console.log (name.substr (0,2)); var name = "kumar" console.log (name); Làm thế nào nó vẫn bất biến
Santosh

97

Ở cấp độ thấp hơn, tính bất biến có nghĩa là bộ nhớ mà chuỗi được lưu trữ sẽ không bị sửa đổi. Khi bạn tạo một chuỗi "foo", một số bộ nhớ sẽ được cấp phát để lưu giá trị "foo". Bộ nhớ này sẽ không bị thay đổi. Nếu bạn sửa đổi chuỗi bằng, chẳng hạn, substr(1)một chuỗi mới được tạo và một phần bộ nhớ khác được cấp phát sẽ lưu trữ "oo". Bây giờ bạn có hai chuỗi trong bộ nhớ, "foo""oo". Ngay cả khi bạn không sử dụng "foo"nữa, nó sẽ bám xung quanh cho đến khi rác được thu gom.

Một lý do tại sao các hoạt động chuỗi tương đối tốn kém.


1
Các con số cũng không thay đổi.
RN Kushwaha

3
xin chào từ năm 2015 !! "Ở cấp độ thấp hơn, tính bất biến có nghĩa là bộ nhớ mà chuỗi được lưu trữ sẽ không bị sửa đổi." --- điều này quá hạn chế và nghe có vẻ không đúng. Tính bất biến chỉ liên quan đến vùng người dùng, bộ nhớ ảo có thể bị thay đổi khi trình cấp phát bộ nhớ thích ngay khi giữ các biến đặc tả ngôn ngữ.
zerkms,

2
Câu trả lời này hợp lý hơn câu trả lời được chấp nhận.
Ejaz Karim

Nhưng tôi có thể làm như var str = 'foo'; tôi có thể sửa đổi qua str = 'bar'. giá trị str đã được sửa đổi theo cách này phải không?
Hacker

@ Hacker Không. Bạn đã gán một chuỗi mới cho biến trỏ đến một vị trí mới trong bộ nhớ.
deceze

13

Bất biến có nghĩa là không thể thay đổi hoặc sửa đổi.

Vì vậy, khi bạn gán một giá trị cho một chuỗi, giá trị này sẽ được tạo từ đầu chứ không phải được thay thế. Vì vậy, mỗi khi một giá trị mới được gán cho cùng một chuỗi, một bản sao sẽ được tạo ra. Vì vậy, trong thực tế, bạn không bao giờ thay đổi giá trị ban đầu.


9

Tôi không chắc chắn về JavaScript, nhưng trong Java, các chuỗi thực hiện một bước bổ sung để không thay đổi, với "Nhóm hằng số chuỗi". Các chuỗi có thể được xây dựng bằng chuỗi chữ ( "foo") hoặc bằng một phương thức Stringkhởi tạo lớp. Các chuỗi được xây dựng bằng các ký tự chuỗi là một phần của Nhóm Hằng số Chuỗi và cùng một chuỗi ký tự sẽ luôn là cùng một địa chỉ bộ nhớ từ nhóm.

Thí dụ:

    String lit1 = "foo";
    String lit2 = "foo";
    String cons = new String("foo");

    System.out.println(lit1 == lit2);      // true
    System.out.println(lit1 == cons);      // false

    System.out.println(lit1.equals(cons)); // true

Ở trên, cả hai lit1lit2đều được xây dựng bằng cách sử dụng cùng một chuỗi ký tự, vì vậy chúng đang trỏ đến cùng một địa chỉ bộ nhớ; lit1 == lit2kết quả là truevì chúng chính xác là cùng một đối tượng.

Tuy nhiên, consđược xây dựng bằng cách sử dụng hàm tạo lớp. Mặc dù tham số là cùng một hằng chuỗi, nhưng hàm tạo sẽ cấp phát bộ nhớ mới cho cons, nghĩa conslà không giống đối tượng lit1lit2mặc dù chứa cùng dữ liệu.

Tất nhiên, vì ba chuỗi đều chứa cùng một dữ liệu ký tự nên việc sử dụng equalsphương thức sẽ trả về true.

(Tất nhiên, cả hai loại cấu trúc chuỗi đều không thay đổi)


3

Bất biến có nghĩa là giá trị không thể thay đổi. Sau khi được tạo, một đối tượng chuỗi không thể được sửa đổi vì nó không thay đổi được. Nếu bạn yêu cầu một chuỗi con của một chuỗi, một Chuỗi mới với phần được yêu cầu sẽ được tạo.

Thay vào đó, sử dụng StringBuffer trong khi thao tác với String làm cho hoạt động hiệu quả hơn vì StringBuffer lưu trữ chuỗi trong một mảng ký tự với các biến để giữ dung lượng của mảng ký tự và độ dài của mảng (Chuỗi ở dạng mảng ký tự)


3

Định nghĩa sách văn bản về khả năng thay đổi có thể chịu trách nhiệm hoặc có thể thay đổi hoặc thay đổi. Trong lập trình, chúng ta dùng từ này để chỉ các đối tượng có trạng thái được phép thay đổi theo thời gian. Một giá trị không thay đổi thì hoàn toàn ngược lại - sau khi nó đã được tạo, nó không bao giờ có thể thay đổi.

Nếu điều này có vẻ lạ, hãy cho phép tôi nhắc bạn rằng nhiều giá trị chúng ta sử dụng mọi lúc trên thực tế là bất biến.

var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);

Tôi nghĩ rằng sẽ không ai ngạc nhiên khi biết rằng dòng thứ hai không có cách nào thay đổi chuỗi trong câu lệnh. Trên thực tế, không có phương thức chuỗi nào thay đổi chuỗi mà chúng hoạt động, chúng đều trả về chuỗi mới. Lý do là các chuỗi là bất biến - chúng không thể thay đổi, chúng ta chỉ có thể tạo chuỗi mới.

Chuỗi không phải là giá trị bất biến duy nhất được tích hợp trong JavaScript. Các con số cũng không thay đổi. Bạn thậm chí có thể tưởng tượng một môi trường mà việc đánh giá biểu thức 2 + 3 sẽ thay đổi ý nghĩa của số 2? Nghe có vẻ vô lý, nhưng chúng tôi làm điều này với các đối tượng và mảng của mình mọi lúc.


2

Từ chuỗi đến ngăn xếp ... một ví dụ đơn giản dễ hiểu được lấy từ blog của Eric Lippert :

Tìm đường dẫn bằng A * trong C # 3.0, Phần hai ...

Một ngăn xếp có thể thay đổi như System.Collections.Generic.Stack rõ ràng là không phù hợp. Chúng tôi muốn có thể lấy một đường dẫn hiện có và tạo đường dẫn mới từ nó cho tất cả các lân cận của phần tử cuối cùng của nó, nhưng việc đẩy một nút mới lên ngăn xếp chuẩn sẽ sửa đổi ngăn xếp. Chúng tôi phải tạo bản sao của ngăn xếp trước khi đẩy nó, điều này thật ngớ ngẩn vì sau đó chúng tôi sẽ sao chép tất cả nội dung của nó một cách không cần thiết.

Các ngăn xếp bất biến không có vấn đề này. Đẩy lên một ngăn xếp bất biến chỉ đơn thuần tạo ra một ngăn xếp hoàn toàn mới liên kết với ngăn xếp cũ làm đuôi của nó. Vì ngăn xếp là không thể thay đổi, nên không có nguy cơ một số mã khác đi cùng và gây rối với nội dung đuôi. Bạn có thể tiếp tục sử dụng ngăn xếp cũ cho nội dung trái tim của bạn.

Để tìm hiểu sâu về tính bất biến, hãy đọc các bài đăng của Eric bắt đầu bằng bài này:

Tính bất biến trong C # Phần một: Các loại tính bất biến


Trích dẫn đó chứa một tuyên bố kỳ quặc - rằng cấu trúc dữ liệu ngăn xếp (thực tế là nhiều ngăn xếp có chia sẻ đuôi), về tổng thể, là một cấu trúc có thể thay đổi - mọi lần đẩy hoặc bật lên đều thay đổi cấu trúc. Chỉ các mục riêng lẻ là bất biến. Và về nguyên tắc, bạn có thể có cùng một cấu trúc nhưng với các yếu tố có thể thay đổi. Điều này xảy ra trong một số biến thể của IIRC tìm thấy công đoàn hoàn tác. Tính bất biến có những lợi thế lớn, nhưng việc chia sẻ một phần hoặc toàn bộ cấu trúc dữ liệu như một cách tối ưu hóa là điều hoàn toàn có thể xảy ra với khả năng thay đổi. Ngay cả khi bạn muốn tính bất biến rõ ràng cho các tham chiếu khác, bạn luôn có thể sao chép-ghi-chép khi cần.
Steve314,

0

Một cách để hiểu khái niệm này là xem cách javascript xử lý tất cả các đối tượng, đó là bằng cách tham khảo. Có nghĩa là tất cả các đối tượng đều có thể thay đổi sau khi được khởi tạo, điều này có nghĩa là bạn có thể thêm một đối tượng với các phương thức và thuộc tính mới. Điều này quan trọng bởi vì nếu bạn muốn một đối tượng là bất biến, đối tượng không thể thay đổi sau khi được khởi tạo.

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.