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ý null
s đú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?
equals
Phương pháp ghi đè để so sánh nội dung của từng trường hợp. Đây là equals
phươ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ề null
tài liệu tham khảoeq
phươ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 equals
sẽ 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ỉAny
LƯ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ề false
nơ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ó Number
phải là BigInt
loạ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 2
sẽ trở lại false
, khi nó chuyển hướng đếnInteger.equals(...)
1 == 2
sẽ 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 AnyRef
new 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 foo
sẽ trở lại true
, trừ trường hợp foo
là null
, sau đó sẽ ném mộtNullPointerException
foo == foo
sẽ trở lại true
, ngay cả khi foo
lànull
foo eq foo
sẽ 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à equals
cho Float
và Double
các loại: Chúng đối xử NaN
khá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, unboxedNan
năng suất false
khi đượ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 equals
trườ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 Any
và 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 NaN
giá trị nguyên thủy nhưng equals
sử 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 NaN
sử dụng isNaN
: