Sự khác biệt giữa ==và .equals()trong Scala, và khi nào nên sử dụng?
Việc triển khai có giống như trong Java không?
EDIT: Câu hỏi liên quan nói về các trường hợp cụ thể của AnyVal. Trường hợp tổng quát hơn là Any.
Sự khác biệt giữa ==và .equals()trong Scala, và khi nào nên sử dụng?
Việc triển khai có giống như trong Java không?
EDIT: Câu hỏi liên quan nói về các trường hợp cụ thể của AnyVal. Trường hợp tổng quát hơn là Any.
Câu trả lời:
Bạn thường sử dụng ==, nó định tuyến đến equals, ngoại trừ việc nó xử lý nulls đúng cách. Tham chiếu bình đẳng (hiếm khi được sử dụng) là eq.
3 == BigInt(3)và BigInt(3) == 3đều đúng. Nhưng, 3.equals(BigInt(3))là sai, trong khi đó BigInt(3).equals(3)là đúng. Do đó, thích sử dụng ==. Tránh sử dụng equals()trong scala. Tôi nghĩ rằng ==chuyển đổi ngầm định tốt, nhưng equals()không.
new java.lang.Integer(1) == new java.lang.Double(1.0)là đúng trong khi new java.lang.Integer(1) equals new java.lang.Double(1.0)là sai?
equalsPhương pháp ghi đè để so sánh nội dung của từng trường hợp. Đây là equalsphương pháp tương tự được sử dụng trong Java==toán tử để so sánh, mà không phải lo lắng về nulltài liệu tham khảoeqphương pháp để kiểm tra xem cả hai đối số có chính xác cùng một tham chiếu không. Không nên sử dụng trừ khi bạn hiểu cách thức hoạt động của nó và thường equalssẽ hoạt động cho những gì bạn cần thay thế. Và đảm bảo chỉ sử dụng điều này với các AnyRefđối số, không chỉAnyLƯU Ý: Trong trường hợp equals, giống như trong Java, nó có thể không trả về kết quả tương tự nếu bạn chuyển đổi các đối số, ví dụ như 1.equals(BigInt(1))sẽ trả về falsenơi nghịch đảo sẽ trả về true. Điều này là do mỗi thực hiện chỉ kiểm tra các loại cụ thể. Các số nguyên thủy không kiểm tra xem đối số thứ hai có Numberphải là BigIntloại hay không mà chỉ là các kiểu nguyên thủy khác
Các AnyRef.equals(Any)phương pháp là một ghi đè bởi lớp con. Một phương thức từ Đặc tả Java cũng đã xuất hiện trên Scala. Nếu được sử dụng trên một cá thể chưa được đóng hộp, nó được đóng hộp để gọi cái này (mặc dù ẩn trong Scala; rõ ràng hơn trong Java với int-> Integer). Việc triển khai mặc định chỉ so sánh các tham chiếu (như trong Java)
Các Any.==(Any)phương pháp so sánh hai đối tượng và cho phép một trong hai tham số là null (như thể gọi một phương thức tĩnh với hai trường hợp). Nó so sánh nếu cả hai là null, sau đó nó gọi equals(Any)phương thức trên thể hiện được đóng hộp.
Các AnyRef.eq(AnyRef)phương pháp so sánh chỉ tài liệu tham khảo, đó là nơi mà các trường hợp nằm trong bộ nhớ. Không có quyền anh ngầm cho phương pháp này.
1 equals 2sẽ trở lại false, khi nó chuyển hướng đếnInteger.equals(...)1 == 2sẽ trở lại false, khi nó chuyển hướng đếnInteger.equals(...)1 eq 2 sẽ không biên dịch, vì nó yêu cầu cả hai đối số phải là kiểu AnyRefnew ArrayList() equals new ArrayList()sẽ trở lại true, vì nó kiểm tra nội dungnew ArrayList() == new ArrayList()sẽ trở lại true, khi nó chuyển hướng đếnequals(...)new ArrayList() eq new ArrayList()sẽ trở lại false, vì cả hai đối số là các trường hợp khác nhaufoo equals foosẽ trở lại true, trừ trường hợp foolà null, sau đó sẽ ném mộtNullPointerExceptionfoo == foosẽ trở lại true, ngay cả khi foolànullfoo eq foosẽ trả về true, vì cả hai đối số liên kết đến cùng một tham chiếuCó một sự khác biệt thú vị giữa ==và equalscho Floatvà Doublecác loại: Chúng đối xử NaNkhác nhau:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Chỉnh sửa: Như đã được chỉ ra trong một nhận xét - "điều này cũng xảy ra trong Java" - phụ thuộc vào chính xác đây là gì:
public static void main(final String... args) {
final double unboxedNaN = Double.NaN;
final Double boxedNaN = Double.valueOf(Double.NaN);
System.out.println(unboxedNaN == unboxedNaN);
System.out.println(boxedNaN == boxedNaN);
System.out.println(boxedNaN.equals(boxedNaN));
}
Cái này sẽ in
false
true
true
Vì vậy, unboxedNannăng suất falsekhi được so sánh bằng nhau vì đây là cách các số dấu phẩy động của IEEE định nghĩa nó và điều này thực sự sẽ xảy ra trong mọi ngôn ngữ lập trình (mặc dù nó bằng cách nào đó làm rối tung khái niệm nhận dạng).
NaN được đóng hộp mang lại kết quả đúng cho việc so sánh sử dụng ==trong Java khi chúng ta so sánh các tham chiếu đối tượng.
Tôi không có lời giải thích cho equalstrường hợp này, IMHO nó thực sự nên hoạt động giống như ==trên các giá trị kép không được đóng hộp, nhưng thực tế thì không.
Dịch sang Scala vấn đề phức tạp hơn một chút vì Scala đã hợp nhất các loại đối tượng và nguyên thủy thành Anyvà dịch thành đôi nguyên thủy và Double đóng hộp khi cần. Do đó, scala ==rõ ràng tập trung vào việc so sánh các NaNgiá trị nguyên thủy nhưng equalssử dụng giá trị được xác định trên các giá trị Double được đóng hộp (có rất nhiều phép thuật chuyển đổi ngầm đang diễn ra và có những thứ được đưa lên gấp đôi RichDouble).
Nếu bạn thực sự cần phải tìm hiểu nếu một cái gì đó thực sự được NaNsử dụng isNaN: