1. So sánh

Các lập trình viên luôn cần so sánh các biến khác nhau với nhau. Nhưng, như bạn đã thấy, mọi thứ không đơn giản như vậy.

Các số nguyên rất dễ so sánh — bạn chỉ cần sử dụng ==là xong. Để so sánh các số thực , bạn phải so sánh hiệu của chúng (hay đúng hơn là giá trị tuyệt đối của hiệu) với một số rất nhỏ.

So sánh các chuỗi thậm chí còn khó hơn. Trên hết, điều này là do chuỗi là đối tượng. Hơn nữa, các lập trình viên thường muốn so sánh chuỗi khác đi một chút tùy thuộc vào tình huống.


2. Cách sắp xếp bộ nhớ chuỗi

Như bạn đã thấy, chuỗi được lưu trữ trong bộ nhớ khác với số nguyên và số thực:

Bộ nhớ sắp xếp các chuỗi như thế nào

Hai khối bộ nhớ được sử dụng để lưu trữ các chuỗi: một khối lưu trữ chính văn bản (kích thước của nó phụ thuộc vào kích thước của văn bản) trong khi khối thứ hai (4 byte) lưu trữ địa chỉ của khối đầu tiên.

Mặc dù một lập trình viên có kinh nghiệm sẽ nói điều gì đó như " String strbiến lưu trữ một tham chiếu đến một Stringđối tượng.


3. Gán tham chiếu cho một chuỗi

Lợi ích của phương pháp này trở nên rõ ràng khi bạn cần gán một biến chuỗi cho một biến chuỗi khác. Ví dụ:

String text = "This is a very important message";
String message = text;

Và đây là kết quả bộ nhớ sẽ chứa:

Gán tham chiếu cho một chuỗi

Sau loại thao tác gán này, Stringđối tượng vẫn giữ nguyên vị trí của nó và chỉ địa chỉ của nó (tham chiếu đến đối tượng) được sao chép vào biến message.


4. Làm việc với tham chiếu và đối tượng

Nhưng nếu bạn quyết định chuyển đổi một chuỗi thành chữ hoa (chữ in hoa), máy Java sẽ làm đúng mọi thứ: bạn sẽ có hai Stringđối tượng và các biến textmessagesẽ lưu trữ các tham chiếu, mỗi tham chiếu đến đối tượng riêng của nó.

Ví dụ:

String text = "This is a very important message";
String message = text.toUpperCase(); 

Và đây là kết quả bộ nhớ sẽ chứa:

Làm việc với các tham chiếu và đối tượng

Xin lưu ý rằng toUpperCase()phương thức này không thay đổi chuỗi mà nó được gọi. Thay vào đó, nó tạo ra một chuỗi mới (đối tượng mới) và trả về một tham chiếu đến nó.

Làm thế nào về một ví dụ thậm chí thú vị hơn. Giả sử bạn quyết định chuyển một chuỗi tới một Scannerđối tượng (để nó đọc các giá trị từ chuỗi).

Ví dụ:

String text = "10 20 40 80";
Scanner console = new Scanner(text);
int a = console.nextInt();
int b = console.nextInt();

Bạn có thể tìm hiểu thêm về cách Scannerhoạt động của lớp tại đây .

Đây là cách tất cả sẽ được lưu trữ trong bộ nhớ:

Làm việc với các tham chiếu và đối tượng.  lớp máy quét

Trong trường hợp này, một Stringđối tượng duy nhất vẫn còn trong bộ nhớ như cũ — chỉ các tham chiếu đến đối tượng đó mới được truyền xung quanh và lưu trữ trong các biến.


5. So sánh các tham chiếu đến Stringcác đối tượng

Và cuối cùng, chúng ta đã đến phần thú vị: so sánh chuỗi.

Có hai toán tử bạn có thể sử dụng để so sánh các biến chuỗi: ==(bằng) và !=(không bằng). Bạn không thể sử dụng các toán tử "lớn hơn", "nhỏ hơn" hoặc "lớn hơn hoặc bằng" — trình biên dịch sẽ không cho phép điều đó.

Nhưng có một sắc thái thú vị ở đây: cái gì thực sự được lưu trữ trong các biến chuỗi? Đúng vậy: địa chỉ (tham chiếu) đến các đối tượng. Và chính những địa chỉ này sẽ được so sánh:

String text = "Hi";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase(); 

Đây là những gì sẽ có trong bộ nhớ:

So sánh các tham chiếu đến các đối tượng String

Các biến messagetexttham chiếu đến (lưu trữ địa chỉ của) cùng một đối tượng. Nhưng các biến s1s2lưu trữ các tham chiếu đến các đối tượng rất giống nhau nhưng khác biệt.

Và nếu so sánh 4 biến này trong code thì bạn sẽ được kết quả như sau:

Mã số Đầu ra bảng điều khiển
String text = "Hi";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase();
System.out.println(text == message);
System.out.println(text == s1);
System.out.println(s1 == s2); 


true  // The addresses are equal
false // The addresses are different
false // The addresses are different