So sánh ký tự trong chuỗi năm 2024

Tại sao chúng ta xem xét so sánh chuỗi tách biệt với mọi thứ khác? Thực tế là các chuỗi là một chủ đề theo đúng nghĩa của chúng trong lập trình. Đầu tiên, nếu bạn lấy tất cả các chương trình Java đã từng viết, bạn sẽ thấy rằng khoảng 25% đối tượng trong đó là các chuỗi. Vì vậy, chủ đề này là rất quan trọng. Thứ hai, quá trình so sánh các chuỗi thực sự rất khác so với các đối tượng khác. Hãy xem xét một ví dụ đơn giản:


public class Main {
   public static void main[String[] args] {
       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String["CodeGym is the best website for learning Java!"];
       System.out.println[s1 == s2];
   }
}

Đầu ra của bàn điều khiển: sai Nhưng tại sao chúng tôi lại sai? Xét cho cùng, các chuỗi hoàn toàn giống nhau, từng từ một:/ Bạn có thể đoán được lý do: đó là vì toán tử \== so sánh các tham chiếu ! Rõ ràng, s1 và s2 có các địa chỉ khác nhau trong bộ nhớ. Nếu bạn nghĩ về điều đó, thì hãy làm lại ví dụ của chúng tôi:


public class Main {
   public static void main[String[] args] {
       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println[s1 == s2];
   }
}

Bây giờ chúng ta lại có hai tham chiếu, nhưng kết quả hoàn toàn ngược lại: Đầu ra bảng điều khiển: đúng Bối rối một cách bất lực? Hãy tìm hiểu những gì đang xảy ra. Toán tử \== thực sự so sánh các địa chỉ bộ nhớ. Điều này luôn đúng và bạn không cần phải nghi ngờ về điều đó. Điều đó có nghĩa là nếu s1 == s2 trả về true, thì hai chuỗi này có cùng địa chỉ. Và thực sự điều này là đúng! Đã đến lúc giới thiệu với bạn một vùng bộ nhớ đặc biệt để lưu trữ các chuỗi: nhóm chuỗi

Nhóm chuỗi là một khu vực để lưu trữ tất cả các giá trị chuỗi mà bạn tạo trong chương trình của mình. Tại sao nó được tạo ra? Như chúng tôi đã nói trước đây, các chuỗi đại diện cho một tỷ lệ phần trăm lớn của tất cả các đối tượng. Bất kỳ chương trình lớn nào cũng tạo ra rất nhiều chuỗi. Nhóm chuỗi được tạo để tiết kiệm bộ nhớ: các chuỗi được đặt ở đó và sau đó các chuỗi được tạo sau đó tham chiếu đến cùng một vùng bộ nhớ—không cần cấp phát bộ nhớ bổ sung mỗi lần. Mỗi khi bạn viết String = "........" chương trình sẽ kiểm tra xem có một chuỗi giống hệt nhau trong nhóm chuỗi hay không. Nếu có, thì một chuỗi mới sẽ không được tạo. Và tham chiếu mới sẽ trỏ đến cùng một địa chỉ trong nhóm chuỗi [nơi đặt chuỗi giống hệt nhau]. Vì vậy, khi chúng tôi đã viết


String s1 = "CodeGym is the best website for learning Java!";

String s2 = "CodeGym is the best website for learning Java!";

s2 trỏ đến cùng một vị trí với s1 . Câu lệnh đầu tiên tạo một chuỗi mới trong nhóm chuỗi. Câu lệnh thứ hai chỉ đơn giản đề cập đến cùng một vùng bộ nhớ như s1 . Bạn có thể tạo thêm 500 chuỗi giống hệt nhau và kết quả sẽ không thay đổi. Đợi tí. Nếu đó là sự thật, thì tại sao ví dụ này không hoạt động trước đây?


public class Main {
   public static void main[String[] args] {
       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String["CodeGym is the best website for learning Java!"];
       System.out.println[s1 == s2];
   }
}

Tôi nghĩ rằng trực giác của bạn đã cho bạn biết lý do =] Hãy thử đoán trước khi đọc tiếp. Bạn có thể thấy rằng hai chuỗi này được khai báo theo những cách khác nhau. Một cái có toán tử new và cái còn lại không có nó. Đây là lý do. Khi toán tử mới được sử dụng để tạo một đối tượng, nó sẽ phân bổ mạnh mẽ một vùng bộ nhớ mới cho đối tượng. Và một chuỗi được tạo bằng new không kết thúc trong nhóm chuỗi — nó trở thành một đối tượng riêng biệt, ngay cả khi văn bản của nó hoàn toàn khớp với một chuỗi trong nhóm chuỗi. Đó là, nếu chúng ta viết đoạn mã sau:


public class Main {
   public static void main[String[] args] {
       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String["CodeGym is the best website for learning Java!"];
   }
}

Trong bộ nhớ, nó trông như thế này:

Và mỗi khi bạn tạo một đối tượng mới bằng cách sử dụng new , một vùng bộ nhớ mới sẽ được cấp phát, ngay cả khi văn bản bên trong chuỗi mới giống nhau! Có vẻ như chúng ta đã tìm ra toán tử \== . Nhưng còn người mới quen của chúng ta, phương thức equals[] thì sao ?


public class Man {
   int geneticCode;
   public static void main[String[] args] {
       Man man1 = new Man[];
       man1.geneticCode = 1111222233;
       Man man2 = new Man[];
       man2.geneticCode = 1111222233;
       System.out.println[man1 == man2];
   }
}

0

Đầu ra bảng điều khiển: đúng Thú vị. Chúng tôi chắc chắn rằng s1 và s2 trỏ đến các vùng khác nhau trong bộ nhớ. Nhưng phương thức equals[] vẫn cho chúng ta biết chúng bằng nhau. Tại sao? Hãy nhớ rằng trước đây chúng ta đã nói rằng phương thức equals[] có thể bị ghi đè để so sánh các đối tượng theo cách chúng ta muốn? Đó chỉ là những gì họ đã làm với lớp String . Nó ghi đè bằng[]phương pháp. Và thay vì so sánh các tham chiếu, nó so sánh chuỗi ký tự trong chuỗi. Nếu văn bản giống nhau, thì việc chúng được tạo ra như thế nào hoặc chúng được lưu trữ ở đâu không quan trọng: cho dù trong nhóm chuỗi hay một vùng bộ nhớ riêng biệt. Kết quả so sánh sẽ đúng. Nhân tiện, Java cho phép bạn thực hiện so sánh chuỗi không phân biệt chữ hoa chữ thường. Thông thường, nếu một trong các chuỗi có tất cả các chữ cái viết hoa, thì kết quả so sánh sẽ là sai:


public class Man {
   int geneticCode;
   public static void main[String[] args] {
       Man man1 = new Man[];
       man1.geneticCode = 1111222233;
       Man man2 = new Man[];
       man2.geneticCode = 1111222233;
       System.out.println[man1 == man2];
   }
}

1

Đầu ra của bàn điều khiển: sai Để so sánh không phân biệt chữ hoa chữ thường, lớp Chuỗi có phương thức equalsIgnoreCase[] . Bạn có thể sử dụng nó nếu bạn chỉ quan tâm đến việc so sánh chuỗi ký tự cụ thể hơn là trường hợp chữ cái. Ví dụ: điều này có thể hữu ích khi so sánh hai địa chỉ:


public class Man {
   int geneticCode;
   public static void main[String[] args] {
       Man man1 = new Man[];
       man1.geneticCode = 1111222233;
       Man man2 = new Man[];
       man2.geneticCode = 1111222233;
       System.out.println[man1 == man2];
   }
}

2

Trong trường hợp này, rõ ràng là chúng ta đang nói về cùng một địa chỉ, vì vậy sẽ hợp lý khi sử dụng phương thức equalsIgnoreCase[] .

Phương thức String.intern[]

Lớp String có một phương thức phức tạp hơn: intern[] ; Phương thức intern[] hoạt động trực tiếp với nhóm chuỗi. Nếu bạn gọi phương thức intern[] trên một số chuỗi:

  • Nó kiểm tra xem có một chuỗi phù hợp trong nhóm chuỗi
  • Nếu có, nó trả về tham chiếu đến chuỗi trong nhóm
  • Nếu không, nó sẽ thêm chuỗi vào nhóm chuỗi và trả về một tham chiếu đến chuỗi đó.

Sau khi sử dụng phương thức intern[] trên tham chiếu chuỗi thu được bằng new , chúng ta có thể sử dụng toán tử \== để so sánh nó với tham chiếu chuỗi từ nhóm chuỗi.


public class Man {
   int geneticCode;
   public static void main[String[] args] {
       Man man1 = new Man[];
       man1.geneticCode = 1111222233;
       Man man2 = new Man[];
       man2.geneticCode = 1111222233;
       System.out.println[man1 == man2];
   }
}

3

Đầu ra của bảng điều khiển: true Khi chúng tôi so sánh các chuỗi này trước đây mà không có intern[] , kết quả là sai. Bây giờ, phương thức intern[] kiểm tra xem chuỗi "CodeGym có phải là trang web tốt nhất để học Java hay không!" nằm trong nhóm chuỗi. Tất nhiên, đó là: chúng tôi đã tạo ra nó với


public class Man {
   int geneticCode;
   public static void main[String[] args] {
       Man man1 = new Man[];
       man1.geneticCode = 1111222233;
       Man man2 = new Man[];
       man2.geneticCode = 1111222233;
       System.out.println[man1 == man2];
   }
}

4

Chúng tôi kiểm tra xem s1 và tham chiếu được trả về bởi s2.intern[] có trỏ đến cùng một vùng bộ nhớ hay không. Và tất nhiên là có :] Tóm lại, hãy ghi nhớ và áp dụng quy tắc quan trọng này: LUÔN LUÔN sử dụng phương thức equals[] để so sánh các chuỗi! Khi so sánh các chuỗi, hầu như chúng ta luôn muốn so sánh các ký tự của chúng hơn là so sánh các tham chiếu, vùng bộ nhớ hoặc bất kỳ thứ gì khác. Phương thức equals[] thực hiện chính xác những gì bạn cần. Để củng cố những gì bạn đã học, chúng tôi khuyên bạn nên xem một video bài học từ Khóa học Java của chúng tôi

Chủ Đề