Làm cách nào để so sánh các chuỗi trong Java?


724

Tôi đã sử dụng ==toán tử trong chương trình của tôi để so sánh tất cả các chuỗi của tôi cho đến nay. Tuy nhiên, tôi đã gặp phải một lỗi, thay đổi một trong số chúng thành .equals()thay thế và nó đã sửa lỗi.

==xấu? Khi nào nên và không nên sử dụng? Có gì khác biệt?


12
Ngoài ra, cũng tốt để biết rằng, nếu bạn đang ghi đè phương thức .equals (), hãy đảm bảo rằng bạn đang ghi đè phương thức .hashcode (), nếu không, bạn sẽ kết thúc bằng việc vi phạm quan hệ tương đương b / w bằng và mã băm. Để biết thêm thông tin tham khảo tài liệu java.
Nageswaran

Để lại một liên kết đến lời giải thích của tôi về lý do tại sao nó ==hoạt động như vậy trên các Đối tượng: stackoverflow.com/a/19966154/2284641
Johannes H.

==sẽ hoạt động đôi khi, vì java có một chuỗi String, nơi nó cố gắng sử dụng lại các tham chiếu bộ nhớ của các chuỗi thường được sử dụng. Nhưng ==so sánh rằng các đối tượng là bằng nhau, không phải là các giá trị ... đó .equals()là cách sử dụng phù hợp mà bạn muốn sử dụng.
James Oravec

Không bao giờ sử dụng == để kiểm tra xem các Chuỗi có giống nhau hay không, trừ khi bạn thích theo dõi các lỗi tinh vi và nghiên cứu các vấn đề phức tạp của quy trình thực hiện Chuỗi Java. "12"=="1"+2là sai (có thể)
Chuyến bay Odyssey

Câu trả lời:


5561

== kiểm tra sự bằng nhau tham chiếu (cho dù chúng là cùng một đối tượng).

.equals() kiểm tra sự bằng nhau về giá trị (cho dù chúng là "bằng nhau" một cách hợp lý).

Các đối tượng.equals () kiểm tra nulltrước khi gọi .equals()để bạn không phải (có sẵn kể từ JDK7, cũng có sẵn trong Guava ).

Do đó, nếu bạn muốn kiểm tra xem hai chuỗi có cùng giá trị hay không, bạn có thể sẽ muốn sử dụng Objects.equals().

// These two have the same value
new String("test").equals("test") // --> true 

// ... but they are not the same object
new String("test") == "test" // --> false 

// ... neither are these
new String("test") == new String("test") // --> false 

// ... but these are because literals are interned by 
// the compiler and thus refer to the same object
"test" == "test" // --> true 

// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true

// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true

Bạn hầu như luôn muốn sử dụng Objects.equals(). Trong trường hợp hiếm hoi mà bạn biết bạn đang xử lý các chuỗi được thực hiện , bạn có thể sử dụng ==.

Từ JLS 3.10.5. Chuỗi ký tự :

Hơn nữa, một chuỗi ký tự luôn luôn đề cập đến cùng một thể hiện của lớp String. Điều này là do các chuỗi ký tự - hay nói chung hơn là các chuỗi là các giá trị của biểu thức hằng ( §15.28 ) - được "tập trung" để chia sẻ các thể hiện duy nhất, sử dụng phương thức String.intern.

Các ví dụ tương tự cũng có thể được tìm thấy trong JLS 3.10.5-1 .

Các phương pháp khác để xem xét

Bình đẳng giá trị String.equalsIgnoreCase () mà bỏ qua trường hợp.

String.contentEquals () so sánh nội dung của Stringvới nội dung của bất kỳ CharSequence(có sẵn kể từ Java 1.5). Giúp bạn không phải biến StringBuffer, v.v. thành Chuỗi trước khi thực hiện so sánh đẳng thức, nhưng để lại kiểm tra null cho bạn.


3
Nếu == kiểm tra sự bằng nhau tham chiếu tại sao n == 5 có ý nghĩa? 5 không phải là một biến
Hrit Roy

2
@HritRoy Vì ==kiểm tra giá trị của một biến. Khi bạn có một đối tượng, biến tham chiếu đối tượng có tham chiếu là đối tượng làm giá trị . Vì vậy, bạn so sánh các tham chiếu khi so sánh hai biến với ==. Khi so sánh một kiểu dữ liệu nguyên thủy như int, nó vẫn giống như vậy. Một biến kiểu intcó số nguyên là giá trị. Vì vậy, bạn so sánh các giá trị của hai ints bằng cách sử dụng ==. Nếu intgiá trị của biến hoặc số ma thuật không thành vấn đề. Ngoài ra: Một tham chiếu không là gì ngoài một số đề cập đến bộ nhớ.
akuzminykh

718

==kiểm tra tham chiếu đối tượng, .equals()kiểm tra các giá trị chuỗi.

Đôi khi, nó trông giống như ==so sánh các giá trị, bởi vì Java thực hiện một số công cụ hậu trường để đảm bảo các chuỗi trong dòng giống hệt nhau thực sự là cùng một đối tượng.

Ví dụ:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

Nhưng hãy cẩn thận với nulls!

==xử lý nullchuỗi tốt, nhưng gọi .equals()từ chuỗi null sẽ gây ra ngoại lệ:

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

Vì vậy, nếu bạn biết rằng nó fooString1có thể là null, hãy nói với người đọc rằng bằng cách viết

System.out.print(fooString1 != null && fooString1.equals("bar"));

Dưới đây là ngắn hơn, nhưng ít rõ ràng hơn là nó kiểm tra null:

System.out.print("bar".equals(fooString1));  // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar"));  // Java 7 required

86
Đôi khi nó trông như thể "==" so sánh giá trị, - == làm giá trị luôn luôn so sánh! (Chỉ là các giá trị nhất định là tài liệu tham khảo!)
aioobe

6
Than ôi, không có phương thức tĩnh nào cho isNullOrEmpty () và không có quá tải tùy chỉnh của các toán tử, điều này làm cho phần này của Java clunkier hơn trong C # hoặc Python. Và vì Java không có các phương thức mở rộng, bạn không thể viết tiện ích của riêng mình để mở rộng java.lang.String. Đúng? Bạn có suy nghĩ gì về Chuỗi phân lớp, thêm phương thức tiện ích tĩnh đó và sau đó luôn luôn sử dụng MyString không? Một phương thức tĩnh có hai tham số để thực hiện so sánh null an toàn cũng sẽ rất hay khi có trong lớp con đó.
Jon Coombs

7
Groovy làm cho điều này dễ dàng hơn một chút với toán tử điều hướng an toàn ( groovy.codehaus.org/ - ) , ?.. Điều đó sẽ chuyển đổi nullString1?.equals(nullString2);thành một tuyên bố hoàn toàn null. Tuy nhiên, nó không có ích nếu bạn có validString?.equals(nullString);- điều đó vẫn ném một ngoại lệ.
Charles Wood

5
Các phương thức ngắn để so sánh các chuỗi rỗng trong java: stackoverflow.com/questions/11271554/
Khăn

5
@JonCoombs Java hỗ trợ phân lớp và tạo phương thức riêng. Tuy nhiên, một vài lớp được đánh dấu cuối cùng vì một số lý do, String là một trong số chúng vì vậy chúng tôi không thể mở rộng. Chúng ta có thể tạo lớp khác và tạo lớp tiện ích ở đó lấy hai chuỗi làm đối số và triển khai logic của chúng ở đó. Ngoài ra để kiểm tra null một số thư viện khác như spring và apache, bộ sưu tập phương thức tốt, người ta có thể sử dụng nó.
Panther

442

== so sánh các tham chiếu đối tượng.

.equals() so sánh các giá trị chuỗi.

Đôi khi ==đưa ra ảo tưởng về việc so sánh các giá trị Chuỗi, như trong các trường hợp sau:

String a="Test";
String b="Test";
if(a==b) ===> true

Điều này là do khi bạn tạo bất kỳ chuỗi ký tự nào, JVM trước tiên tìm kiếm chữ đó trong nhóm Chuỗi và nếu tìm thấy kết quả khớp, tham chiếu tương tự đó sẽ được cung cấp cho Chuỗi mới. Vì điều này, chúng tôi nhận được:

(a == b) ===> đúng

                       String Pool
     b -----------------> "test" <-----------------a

Tuy nhiên, ==thất bại trong trường hợp sau:

String a="test";
String b=new String("test");
if (a==b) ===> false

Trong trường hợp này cho new String("test")câu lệnh, String mới sẽ được tạo trên heap và tham chiếu đó sẽ được cung cấp cho b, do đó bsẽ được cung cấp một tham chiếu trên heap, không phải trong nhóm String.

Bây giờ ađang trỏ đến một Chuỗi trong nhóm Chuỗi trong khi bđang trỏ đến một Chuỗi trên heap. Do đó, chúng tôi nhận được:

if (a == b) ===> sai.

                String Pool
     "test" <-------------------- a

                   Heap
     "test" <-------------------- b

Mặc dù .equals()luôn so sánh giá trị của Chuỗi để nó đúng trong cả hai trường hợp:

String a="Test";
String b="Test";
if(a.equals(b)) ===> true

String a="test";
String b=new String("test");
if(a.equals(b)) ===> true

Vì vậy, sử dụng .equals()luôn luôn tốt hơn.


3
.equals () so sánh hai trường hợp tuy nhiên bằng nhau được thực hiện để so sánh chúng. Điều đó có thể hoặc không thể so sánh đầu ra của toString.
Jacob

3
.equals()Phương thức lớp đối tượng @Jacob so sánh các thể hiện (tham chiếu / Địa chỉ) trong đó .equals()phương thức lớp Chuỗi được ghi đè để so sánh nội dung (ký tự)
Satyadev

1
Tốt chỉ ra chuỗi String so với sự khác biệt của heap Java vì chúng chắc chắn không giống nhau. Trong nhóm chuỗi, Java cố gắng "lưu trữ" Stringcác đối tượng để lưu dấu chân bộ nhớ như Stringđược biết là không thay đổi (tôi hy vọng, tôi nói nó chính xác ở đây). Đồng thời kiểm tra stackoverflow.com/questions/3052442/ Mạnh
Roland

1
Đây là câu trả lời tôi đang tìm kiếm.
Cuối tuần

Thật là một câu trả lời tuyệt vời!
alwbtc


179

Các chuỗi trong Java là bất biến. Điều đó có nghĩa là bất cứ khi nào bạn cố gắng thay đổi / sửa đổi chuỗi bạn sẽ có một thể hiện mới. Bạn không thể thay đổi chuỗi gốc. Điều này đã được thực hiện để các trường hợp chuỗi này có thể được lưu trữ. Một chương trình điển hình chứa nhiều tham chiếu chuỗi và lưu trữ các bộ đệm này có thể làm giảm dung lượng bộ nhớ và tăng hiệu suất của chương trình.

Khi sử dụng toán tử == để so sánh chuỗi, bạn không so sánh nội dung của chuỗi, nhưng thực tế là so sánh địa chỉ bộ nhớ. Nếu cả hai đều bằng nhau, nó sẽ trả về đúng và sai. Trong khi đó bằng với chuỗi so sánh các nội dung chuỗi.

Vì vậy, câu hỏi là nếu tất cả các chuỗi được lưu trữ trong hệ thống, làm thế nào ==trả về sai trong khi bằng trả về đúng? Vâng, điều này là có thể. Nếu bạn tạo một chuỗi mới như String str = new String("Testing")cuối cùng bạn sẽ tạo một chuỗi mới trong bộ đệm ngay cả khi bộ đệm đã chứa một chuỗi có cùng nội dung. Tóm lại "MyString" == new String("MyString")sẽ luôn trả về sai.

Java cũng nói về hàm intern () có thể được sử dụng trên một chuỗi để biến nó thành một phần của bộ đệm nên "MyString" == new String("MyString").intern()sẽ trả về true.

Lưu ý: Toán tử == nhanh hơn nhiều so với bằng chỉ vì bạn đang so sánh hai địa chỉ bộ nhớ, nhưng bạn cần chắc chắn rằng mã không tạo ra các thể hiện Chuỗi mới trong mã. Nếu không bạn sẽ gặp lỗi.


147
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true

Hãy chắc chắn rằng bạn hiểu lý do tại sao. Đó là vì sự ==so sánh chỉ so sánh các tài liệu tham khảo; các equals()phương pháp thực hiện một sự so sánh nhân vật theo từng ký tự của nội dung.

Khi bạn gọi mới cho ab, mỗi cái sẽ có một tham chiếu mới trỏ đến "foo"bảng chuỗi. Các tài liệu tham khảo là khác nhau, nhưng nội dung là như nhau.


128

Phải, thật tệ ...

==có nghĩa là hai tham chiếu chuỗi của bạn chính xác là cùng một đối tượng. Bạn có thể đã nghe nói rằng đây là trường hợp vì Java giữ một bảng theo nghĩa đen (mà nó làm), nhưng đó không phải là luôn luôn như vậy. Một số chuỗi được tải theo nhiều cách khác nhau, được xây dựng từ các chuỗi khác, v.v., vì vậy bạn không bao giờ được cho rằng hai chuỗi giống nhau được lưu trữ trong cùng một vị trí.

Bằng không so sánh thực sự cho bạn.


124

Có, ==rất tệ khi so sánh Chuỗi (thực sự là bất kỳ đối tượng nào, trừ khi bạn biết chúng là hợp quy). ==chỉ so sánh các tham chiếu đối tượng. .equals()kiểm tra sự bình đẳng. Đối với Chuỗi, thường thì chúng sẽ giống nhau nhưng như bạn đã khám phá, điều đó không luôn được đảm bảo.


118

Java có một chuỗi String, theo đó Java quản lý cấp phát bộ nhớ cho các đối tượng String. Xem chuỗi hồ bơi trong Java

Khi bạn kiểm tra (so sánh) hai đối tượng bằng ==toán tử, nó sẽ so sánh sự bằng nhau của địa chỉ với nhóm chuỗi. Nếu hai đối tượng String có tài liệu tham khảo cùng một địa chỉ thì nó sẽ trả về true, nếu không false. Nhưng nếu bạn muốn so sánh nội dung của hai đối tượng String thì bạn phải ghi đè equalsphương thức.

equals thực sự là phương thức của lớp Object, nhưng nó được ghi đè vào lớp String và một định nghĩa mới được đưa ra để so sánh nội dung của đối tượng.

Example:
    stringObjectOne.equals(stringObjectTwo);

Nhưng nhớ rằng nó tôn trọng trường hợp của String. Nếu bạn muốn so sánh không phân biệt chữ hoa chữ thường thì bạn phải dùng phương thức equalsIgnoreCase của lớp String.

Hãy xem nào:

String one   = "HELLO"; 
String two   = "HELLO"; 
String three = new String("HELLO"); 
String four  = "hello"; 

one == two;   // TRUE
one == three; // FALSE
one == four;  // FALSE

one.equals(two);            // TRUE
one.equals(three);          // TRUE
one.equals(four);           // FALSE
one.equalsIgnoreCase(four); // TRUE

7
Tôi thấy rằng đây là một câu trả lời muộn cho câu hỏi lớn. Tôi có thể hỏi những gì nó cung cấp mà chưa được đề cập trong các câu trả lời hiện có không?
Bí ẩn

6
@Mysticial anh ấy đã thêm equalsIgnoreCasemà có thể là thông tin cho tươi hơn.
AmitG

103

Tôi đồng ý với câu trả lời từ zacherates.

Nhưng những gì bạn có thể làm là gọi intern()các chuỗi không theo nghĩa đen của bạn.

Từ ví dụ của zacherates:

// ... but they are not the same object
new String("test") == "test" ==> false 

Nếu bạn thực hiện đẳng thức Chuỗi không theo nghĩa đen là true:

new String("test").intern() == "test" ==> true 

8
Điều này thường không phải là một ý tưởng tốt. Thực tập là tương đối tốn kém và có thể (nghịch lý) >> tăng << dấu chân bộ nhớ JVM của bạn và tăng chi phí GC. Trong hầu hết các trường hợp, những điều này vượt trội hơn lợi ích hiệu suất từ ​​việc sử dụng ==để so sánh chuỗi.
Stephen C

101

==so sánh các tham chiếu đối tượng trong Java và điều đó cũng không ngoại lệ đối với Stringcác đối tượng.

Để so sánh nội dung thực tế của các đối tượng (bao gồm String), người ta phải sử dụng equalsphương thức .

Nếu so sánh hai Stringđối tượng sử dụng ==hóa ra là true, đó là do các Stringđối tượng đã được thực hiện và Máy ảo Java đang có nhiều tham chiếu trỏ đến cùng một thể hiện của String. Chúng ta không nên mong đợi rằng so sánh một Stringđối tượng có chứa cùng một nội dung với một Stringđối tượng khác sử dụng ==để đánh giá là true.


99

.equals()so sánh dữ liệu trong một lớp (giả sử chức năng được thực hiện). ==so sánh các vị trí con trỏ (vị trí của đối tượng trong bộ nhớ).

==trả về true nếu cả hai đối tượng (KHÔNG NÓI VỀ GIỚI THIỆU) trỏ đến đối tượng CÙNG. .equals()trả về true nếu hai đối tượng chứa cùng một dữ liệu equals()Versus ==trong Java

Điều đó có thể giúp bạn.


95

==thực hiện kiểm tra đẳng thức tham chiếu , cho dù 2 đối tượng (chuỗi trong trường hợp này) có tham chiếu đến cùng một đối tượng trong bộ nhớ hay không.

Các equals()phương pháp sẽ kiểm tra xem các nội dung hoặc các tiểu bang của 2 đối tượng đều giống nhau.

Rõ ràng ==là nhanh hơn, nhưng sẽ (có thể) cho kết quả sai trong nhiều trường hợp nếu bạn chỉ muốn biết nếu 2 Stringgiây giữ cùng một văn bản.

Chắc chắn việc sử dụng equals()phương pháp được khuyến khích.

Đừng lo lắng về hiệu suất. Một số điều cần khuyến khích sử dụng String.equals():

  1. Việc thực hiện String.equals()kiểm tra đầu tiên cho đẳng thức tham chiếu (sử dụng ==) và nếu 2 chuỗi giống nhau bằng tham chiếu, thì không có phép tính nào nữa được thực hiện!
  2. Nếu tham chiếu 2 chuỗi không giống nhau, String.equals()tiếp theo sẽ kiểm tra độ dài của chuỗi. Đây cũng là một hoạt động nhanh vì Stringlớp lưu trữ độ dài của chuỗi, không cần phải đếm các ký tự hoặc điểm mã. Nếu độ dài khác nhau, không có kiểm tra nào được thực hiện nữa, chúng tôi biết chúng không thể bằng nhau.
  3. Chỉ khi chúng ta đi xa đến mức này, nội dung của 2 chuỗi sẽ thực sự được so sánh và đây sẽ là so sánh ngắn: không phải tất cả các ký tự sẽ được so sánh, nếu chúng ta tìm thấy một ký tự không khớp (ở cùng một vị trí trong 2 chuỗi ), không có ký tự nữa sẽ được kiểm tra.

Khi tất cả được nói và thực hiện, ngay cả khi chúng tôi đảm bảo rằng các chuỗi là thực tập, sử dụng equals()phương thức vẫn không phải là chi phí mà người ta có thể nghĩ, chắc chắn là cách được đề xuất. Nếu bạn muốn kiểm tra tham chiếu hiệu quả, thì hãy sử dụng enum trong đó nó được đảm bảo bởi đặc tả ngôn ngữ và việc triển khai rằng cùng một giá trị enum sẽ là cùng một đối tượng (theo tham chiếu).


2
Obviously == is faster- thực sự là việc thực hiện .equals(String)kiểm tra đầu tiên ==trước bất cứ điều gì khác vì vậy tôi sẽ nói tốc độ là giống hệt nhau.
Razzle Shazl

2
public boolean equals(Object anObject) { if (this == anObject) { return true; } ...
Razzle Shazl

82

Nếu bạn giống tôi, khi tôi mới bắt đầu sử dụng Java, tôi muốn sử dụng toán tử "==" để kiểm tra xem hai cá thể Chuỗi có bằng nhau hay không, nhưng tốt hơn hay xấu hơn, đó không phải là cách chính xác để làm điều đó trong Java.

Trong hướng dẫn này, tôi sẽ trình bày một số cách khác nhau để so sánh chính xác các chuỗi Java, bắt đầu với cách tiếp cận tôi sử dụng hầu hết thời gian. Ở phần cuối của hướng dẫn so sánh Chuỗi Java này, tôi cũng sẽ thảo luận tại sao toán tử "==" không hoạt động khi so sánh các chuỗi Java.

Tùy chọn 1: So sánh chuỗi Java với phương thức bằng nhau Hầu hết thời gian (có thể là 95% thời gian) Tôi so sánh các chuỗi với phương thức bằng của lớp Chuỗi Java, như sau:

if (string1.equals(string2))

Chuỗi này bằng phương thức xem xét hai chuỗi Java và nếu chúng chứa cùng một chuỗi ký tự, chúng được coi là bằng nhau.

Xem xét một ví dụ so sánh Chuỗi nhanh với phương thức bằng, nếu thử nghiệm sau được chạy, hai chuỗi sẽ không được coi là bằng nhau vì các ký tự không giống hệt nhau (trường hợp của các ký tự là khác nhau):

String string1 = "foo";
String string2 = "FOO";

if (string1.equals(string2))
{
    // this line will not print because the
    // java string equals method returns false:
    System.out.println("The two strings are the same.")
}

Nhưng, khi hai chuỗi chứa cùng một chuỗi ký tự, phương thức equals sẽ trả về true, như trong ví dụ này:

String string1 = "foo";
String string2 = "foo";

// test for equality with the java string equals method
if (string1.equals(string2))
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

Tùy chọn 2: So sánh chuỗi với phương thức equalsIgnoreCase

Trong một số bài kiểm tra so sánh chuỗi, bạn sẽ muốn bỏ qua xem các chuỗi là chữ hoa hay chữ thường. Khi bạn muốn kiểm tra các chuỗi của mình xem có bằng nhau theo cách không phân biệt chữ hoa chữ thường này không, hãy sử dụng phương thức equalsIgnoreCase của lớp String, như sau:

String string1 = "foo";
String string2 = "FOO";

 // java string compare while ignoring case
 if (string1.equalsIgnoreCase(string2))
 {
     // this line WILL print
     System.out.println("Ignoring case, the two strings are the same.")
 }

Tùy chọn 3: So sánh chuỗi Java với phương thức so sánh

Ngoài ra còn có một cách thứ ba, ít phổ biến hơn để so sánh các chuỗi Java và đó là phương thức so sánh với lớp String. Nếu hai chuỗi hoàn toàn giống nhau, phương thức so sánh sẽ trả về giá trị 0 (không). Dưới đây là một ví dụ nhanh về cách tiếp cận so sánh Chuỗi này trông như thế nào:

String string1 = "foo bar";
String string2 = "foo bar";

// java string compare example
if (string1.compareTo(string2) == 0)
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

Trong khi tôi viết về khái niệm bình đẳng này trong Java, điều quan trọng cần lưu ý là ngôn ngữ Java bao gồm một phương thức bằng trong lớp Đối tượng Java cơ sở. Bất cứ khi nào bạn đang tạo các đối tượng của riêng mình và bạn muốn cung cấp một phương tiện để xem hai trường hợp của đối tượng của bạn có "bằng nhau" hay không, bạn nên ghi đè (và thực hiện) phương thức này bằng trong lớp của bạn (giống như cách ngôn ngữ Java cung cấp hành vi bình đẳng / so sánh này trong phương thức String bằng).

Bạn có thể muốn xem cái này ==, .equals (), soTo () và so sánh ()


5
đối với chuỗi ký tự như Chuỗi String1 = "thanh foo"; Chuỗi string2 = "thanh foo"; bạn có thể trực tiếp sử dụng toán tử == để kiểm tra sự bình đẳng nội dung
JAVA

1
Trong ứng dụng google, kịch bản "so sánh" không phải là sở hữu. Tôi đã thử instaed "bằng" Đây là giải pháp duy nhất hoạt động ....
user3887038

77

Chức năng:

public float simpleSimilarity(String u, String v) {
    String[] a = u.split(" ");
    String[] b = v.split(" ");

    long correct = 0;
    int minLen = Math.min(a.length, b.length);

    for (int i = 0; i < minLen; i++) {
        String aa = a[i];
        String bb = b[i];
        int minWordLength = Math.min(aa.length(), bb.length());

        for (int j = 0; j < minWordLength; j++) {
            if (aa.charAt(j) == bb.charAt(j)) {
                correct++;
            }
        }
    }

    return (float) (((double) correct) / Math.max(u.length(), v.length()));
}

Kiểm tra:

String a = "This is the first string.";

String b = "this is not 1st string!";

// for exact string comparison, use .equals

boolean exact = a.equals(b);

// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote

float similarity = simple_similarity(a,b);

6
Điều này khác với những câu trả lời khác như thế nào? và tại sao làm theo cách bạn đề xuất
user151019

2
@Mark Câu hỏi về sự khác biệt giữa ==equalsđã được trả lời bởi các giải pháp khác, tôi chỉ đưa ra một cách khác để so sánh các chuỗi một cách lỏng lẻo
Khaled.K

77

Các ==kiểm toán nếu hai tham chiếu trỏ đến cùng một đối tượng hay không. .equals()kiểm tra nội dung chuỗi thực tế (giá trị).

Lưu ý rằng .equals()phương thức thuộc về lớpObject (siêu lớp của tất cả các lớp). Bạn cần ghi đè nó theo yêu cầu lớp của bạn, nhưng đối với Chuỗi, nó đã được triển khai và kiểm tra xem hai chuỗi có cùng giá trị hay không.

  • Trường hợp 1

    String s1 = "Stack Overflow";
    String s2 = "Stack Overflow";
    s1 == s2;      //true
    s1.equals(s2); //true

    Lý do: Chuỗi ký tự được tạo mà không có null được lưu trữ trong nhóm Chuỗi trong vùng permgen của heap. Vì vậy, cả s1 và s2 đều trỏ đến cùng một đối tượng trong nhóm.

  • Trường hợp 2

    String s1 = new String("Stack Overflow");
    String s2 = new String("Stack Overflow");
    s1 == s2;      //false
    s1.equals(s2); //true

    Lý do: Nếu bạn tạo một đối tượng String bằng newtừ khóa, một không gian riêng được phân bổ cho nó trên heap.


53

==so sánh giá trị tham chiếu của các đối tượng trong khi equals()phương thức có trong java.lang.Stringlớp so sánh nội dung của Stringđối tượng (với đối tượng khác).


15
không phải là kén chọn, nhưng equals()phương pháp cho Stringthực sự là trong Stringlớp, không phải trong Object. Mặc định equals()trong Objectsẽ không so sánh rằng các nội dung là như nhau và trên thực tế chỉ trả về đúng khi tham chiếu giống nhau.
Jacob Schoen

1
@JacobSchoen: Liên kết trên không hoạt động nữa vì GrepCode không hoạt động. Đây là giải pháp thay thế cho việc thực hiện bằng: [Liên kết nội tuyến] ( zgrepcode.com/java/openjdk/10.0.2/java.base/java/lang/iêu )
Amandeep Singh

50

Tôi nghĩ rằng khi bạn xác định một Stringbạn xác định một đối tượng. Vì vậy, bạn cần phải sử dụng .equals(). Khi bạn sử dụng các kiểu dữ liệu nguyên thủy bạn sử dụng ==nhưng với String(và bất kỳ đối tượng nào), bạn phải sử dụng .equals().


7
"char []" không phải là kiểu dữ liệu nguyên thủy! Đó là một mảng của "char". Và mảng không phải là kiểu dữ liệu nguyên thủy.
Christian

48

Nếu equals()phương thức có mặt trong java.lang.Objectlớp và dự kiến ​​sẽ kiểm tra sự tương đương của trạng thái của các đối tượng! Điều đó có nghĩa là, nội dung của các đối tượng. Trong đó ==toán tử dự kiến ​​sẽ kiểm tra các thể hiện đối tượng thực tế có giống nhau hay không.

Thí dụ

Xem xét hai biến tham chiếu khác nhau str1str2:

str1 = new String("abc");
str2 = new String("abc");

Nếu bạn sử dụng equals()

System.out.println((str1.equals(str2))?"TRUE":"FALSE");

Bạn sẽ nhận được đầu ra như TRUEthể bạn sử dụng ==.

System.out.println((str1==str2) ? "TRUE" : "FALSE");

Bây giờ bạn sẽ nhận được FALSEđầu ra là, bởi vì cả hai str1str2đang trỏ đến hai đối tượng khác nhau mặc dù cả hai đều có cùng nội dung chuỗi. Đó là bởi vì new String()một đối tượng mới được tạo ra mỗi lần.


43

Toán tử == luôn có nghĩa là để so sánh tham chiếu đối tượng , trong khi phương thức .equals () của lớp String bị ghi đè để so sánh nội dung :

String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)

40

Tất cả các đối tượng được đảm bảo có một .equals()phương thức vì Object chứa một phương thức, .equals()trả về một boolean. Đây là công việc của lớp con để ghi đè phương thức này nếu cần một định nghĩa xác định thêm. Không có nó (tức là sử dụng ==), chỉ có các địa chỉ bộ nhớ được kiểm tra giữa hai đối tượng cho sự bằng nhau. Chuỗi ghi đè lên điều này.equals() phương thức và thay vì sử dụng địa chỉ bộ nhớ, nó trả về việc so sánh các chuỗi ở cấp độ ký tự cho bằng.

Một lưu ý chính là các chuỗi được lưu trữ trong một nhóm gộp, do đó, khi một chuỗi được tạo, nó sẽ được lưu trữ mãi mãi trong một chương trình tại cùng một địa chỉ. Chuỗi không thay đổi, chúng là bất biến. Đây là lý do tại sao nên sử dụng nối chuỗi thường xuyên nếu bạn có quá trình xử lý chuỗi nghiêm trọng. Thay vào đó bạn sẽ sử dụng các StringBuilderlớp được cung cấp. Hãy nhớ rằng các con trỏ tới chuỗi này có thể thay đổi và nếu bạn quan tâm xem liệu hai con trỏ có giống nhau ==không thì sẽ là một cách tốt để đi. Bản thân dây thì không.


2
"một khi một chuỗi được tạo, nó sẽ được lưu trữ mãi mãi trong một chương trình tại cùng một địa chỉ" - Điều này không đúng. Chỉ các biểu thức chuỗi hằng số thời gian biên dịch (có thể liên quan đến final Stringcác biến) và các chuỗi mà chương trình của bạn thực tập rõ ràng được lưu trữ trong cái mà bạn gọi là "nhóm gộp". Tất cả các Stringđối tượng khác phải chịu bộ sưu tập rác một khi không còn tham chiếu trực tiếp đến chúng, giống như bất kỳ loại đối tượng nào khác. Ngoài ra, trong khi tính không thay đổi là cần thiết để toàn bộ cơ chế thực tập hoạt động, thì mặt khác nó không liên quan đến điều này.
Ted Hopp

So sánh chuỗi được thực hiện thông qua phương thức equals hoặc equalsIgnoreCase thực sự so sánh nội dung của chuỗi. Nhưng == ký chỉ kiểm tra các giá trị tham chiếu. Đối với chuỗi ký tự từ chuỗi nhóm sẽ hoạt động tốt trong trường hợp này. Chuỗi s1 = Chuỗi mới ("a"); Chuỗi s2 = Chuỗi mới ("a"); trong trường hợp này s1 == s2 là sai, nhưng s1.equals (s2) là đúng.
Shailendra Singh

39

Bạn cũng có thể sử dụng compareTo()phương thức để so sánh hai Chuỗi. Nếu kết quả so sánh bằng 0, thì hai chuỗi bằng nhau, nếu không các chuỗi được so sánh không bằng nhau.

Việc ==so sánh các tham chiếu và không so sánh các chuỗi thực tế. Nếu bạn đã tạo mọi chuỗi bằng cách sử dụng new String(somestring).intern()thì bạn có thể sử dụng ==toán tử để so sánh hai chuỗi, nếu không các phương thức bằng () hoặc so sánh chỉ có thể được sử dụng.


35

Trong Java, khi toán tử Viking == được sử dụng để so sánh 2 đối tượng, nó sẽ kiểm tra xem các đối tượng có tham chiếu đến cùng một vị trí trong bộ nhớ hay không. Nói cách khác, nó kiểm tra xem 2 tên đối tượng về cơ bản có tham chiếu đến cùng một vị trí bộ nhớ hay không.

Lớp Chuỗi Java thực sự ghi đè triển khai bằng () mặc định trong lớp Đối tượng - và nó ghi đè phương thức để nó chỉ kiểm tra các giá trị của chuỗi, chứ không phải vị trí của chúng trong bộ nhớ. Điều này có nghĩa là nếu bạn gọi phương thức equals () để so sánh 2 đối tượng String, thì miễn là chuỗi ký tự thực tế bằng nhau, cả hai đối tượng đều được coi là bằng nhau.

Các ==kiểm tra hành nếu hai chuỗi là chính xác cùng một đối tượng.

Các .equals()kiểm tra phương pháp nếu hai chuỗi có cùng giá trị.


1
trừ khi một trong số chúng là null, vì s.equals (s2) sẽ sập nếu s là null, khiến cho việc so sánh không thành công. Tất nhiên, điều này không thực sự mâu thuẫn với câu trả lời; nó chỉ là một lời cảnh báo.
Jon Coombs

1
Không, nó sẽ không sụp đổ, nó sẽ ném NullPulumException, khiến cho việc so sánh không diễn ra.
Bludzee
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.