2009-07-29 23 views
164

Tôi biết rằng == có một số vấn đề khi so sánh hai Strings. Có vẻ như là String.equals() là một cách tiếp cận tốt hơn. Vâng, tôi đang làm thử nghiệm JUnit và độ nghiêng của tôi là sử dụng assertEquals(str1, str2). Đây có phải là cách đáng tin cậy để khẳng định hai Chuỗi chứa nội dung giống nhau không? Tôi sẽ sử dụng assertTrue(str1.equals(str2)), nhưng sau đó bạn không nhận được lợi ích khi thấy giá trị dự kiến ​​và thực tế là gì trên thất bại.Java: Có phải khẳng địnhEquals (String, String) đáng tin cậy không?

Trên ghi chú có liên quan, có ai có liên kết đến trang hoặc chuỗi giải thích rõ ràng sự cố với str1 == str2 không?

+1

Nếu bạn không chắc chắn, bạn có thể đọc mã hoặc Javadoc. BTW nếu bạn muốn kiểm tra chúng là cùng một đối tượng, bạn có thể sử dụng assertSame. –

+2

Nếu str1 và str2 là null, assertEquals() là true, nhưng assertTrue (str1.equals (str2)) ném một ngoại lệ. Ví dụ đầu tiên cũng sẽ in một thông báo lỗi hữu ích như nội dung của str1 và str2, thứ hai thì không. –

Trả lời

226

Bạn nên luôn sử dụng .equals() khi so sánh Strings trong Java.

JUnit gọi phương thức .equals() để xác định sự bình đẳng trong phương pháp assertEquals(Object o1, Object o2).

Vì vậy, bạn chắc chắn an toàn khi sử dụng assertEquals(string1, string2). (Bởi vì String s là Object s)

Here is a link to a great Stackoverflow question liên quan đến một số khác biệt giữa ==.equals().

+11

IIRC assertEquals() thành công nếu cả hai chuỗi là null. Nếu đây không phải là những gì bạn muốn sau đó gọi assertNotNull() là tốt. – finnw

+0

@finnw, kiểm tra nguồn, bạn thực sự là chính xác. –

+10

Ngoài ra, nếu bạn muốn thử nghiệm cho ==, bạn có thể gọi assertSame() – james

3

Có, nó được sử dụng tất cả thời gian để thử nghiệm. Rất có thể khuôn khổ thử nghiệm sử dụng .equals() để so sánh như vậy.

Dưới đây là liên kết giải thích "lỗi bình đẳng chuỗi". Về cơ bản, các chuỗi trong Java là các đối tượng, và khi bạn so sánh bình đẳng đối tượng, thông thường chúng được so sánh dựa trên địa chỉ bộ nhớ, chứ không phải theo nội dung. Bởi vì điều này, hai chuỗi sẽ không chiếm cùng một địa chỉ, ngay cả khi nội dung của chúng giống hệt nhau, vì vậy chúng sẽ không khớp chính xác, mặc dù chúng trông giống nhau khi được in.

http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/

3
public class StringEqualityTest extends TestCase { 
    public void testEquality() throws Exception { 
     String a = "abcde"; 
     String b = new String(a); 
     assertTrue(a.equals(b)); 
     assertFalse(a == b); 
     assertEquals(a, b); 
    } 
} 
2

JUnit assertEquals(obj1, obj2) thực sự gọi obj1.equals(obj2).

Ngoài ra còn có assertSame(obj1, obj2) mà không obj1 == obj2 (ví dụ, xác nhận rằng obj1obj2 đang tham khảo các ví dụ cùng), đó là những gì bạn đang cố gắng để tránh.

Vì vậy, bạn ổn.

4

Tóm lại - bạn có thể có hai đối tượng String chứa các ký tự giống nhau nhưng là các đối tượng khác nhau (trong các vị trí bộ nhớ khác nhau). Toán tử == kiểm tra xem hai tham chiếu đang trỏ đến cùng một đối tượng (vị trí bộ nhớ), nhưng phương thức equals() sẽ kiểm tra xem các ký tự có giống nhau hay không.

Thông thường bạn quan tâm đến việc kiểm tra xem hai Chuỗi có chứa các ký tự giống nhau không, cho dù chúng có trỏ đến cùng một vị trí bộ nhớ hay không.

+0

Thumbs up, chính xác là giá trị của chuỗi những gì bạn muốn so sánh hoặc giá trị của vị trí bộ nhớ – Pomagranite

26

assertEquals sử dụng phương pháp equals để so sánh. Có một xác nhận khác nhau, assertSame, sử dụng toán tử ==.

Để hiểu lý do tại sao == không nên được sử dụng với chuỗi bạn cần phải hiểu những gì == thực hiện: nó kiểm tra danh tính. Tức là, a == b kiểm tra xem ab có tham chiếu đến cùng một đối tượng hay không. Nó được xây dựng trong ngôn ngữ, và hành vi của nó không thể được thay đổi bởi các lớp khác nhau. Mặt khác, phương pháp equals có thể bị ghi đè bởi các lớp. Mặc dù hành vi mặc định của nó (trong lớp Object) là thực hiện kiểm tra danh tính bằng cách sử dụng toán tử ==, nhiều lớp, bao gồm String, ghi đè lên thay vào đó thực hiện kiểm tra "tương đương". Trong trường hợp của String, thay vì kiểm tra xem ab có đề cập đến cùng một đối tượng hay không, hãy kiểm tra xem các đối tượng mà chúng tham chiếu là cả hai chuỗi có chứa chính xác cùng một ký tự hay không.

Thời gian tương tự: hãy tưởng tượng rằng mỗi đối tượng String là một mẩu giấy có nội dung được viết trên đó. Hãy nói rằng tôi có hai mảnh giấy với "Foo" được viết trên đó, và một cái khác với "Bar" được viết trên đó. Nếu tôi lấy hai mảnh giấy đầu tiên và sử dụng == để so sánh chúng, nó sẽ trả về false vì về cơ bản nó hỏi "có phải cùng một mẩu giấy không?". Nó không cần phải nhìn vào những gì được viết trên giấy. Thực tế là tôi cho nó hai mẩu giấy (thay vì cùng một cái hai lần) có nghĩa là nó sẽ trả về false. Nếu tôi sử dụng equals, tuy nhiên, phương pháp equals sẽ đọc hai mẩu giấy và thấy rằng chúng nói cùng một điều ("Foo"), và vì vậy nó sẽ trả lại true.

Bit gây nhầm lẫn với Strings là Java có khái niệm về chuỗi "interning" và điều này được thực hiện tự động trên bất kỳ chuỗi ký tự nào trong mã của bạn. Điều này có nghĩa là nếu bạn có hai chuỗi ký tự tương đương trong mã của bạn (ngay cả khi chúng ở trong các lớp khác nhau), chúng sẽ thực sự cả hai tham chiếu đến cùng một đối tượng String. Điều này giúp trả lại cho nhà khai thác ==true thường xuyên hơn mức có thể mong đợi.

+0

"Đó là, a == b kiểm tra xem a và b là cùng một đối tượng." kiểm tra xem a và b REFER có cùng một đối tượng hay không, vì a và b là các tham chiếu trừ khi tôi sai, – andy

+0

@ user1903064 đúng. Vì các biến không nguyên thủy chỉ có thể chứa các tham chiếu trong Java, nên bỏ qua phần bổ sung mức độ bất mãn khi nói về chúng, nhưng tôi đồng ý rằng trong trường hợp này rõ ràng hơn là có lợi.Tôi đã cập nhật câu trả lời. Cám ơn vì sự gợi ý! –

Các vấn đề liên quan