Java: Số nguyên bằng so với ==


152

Tính đến Java 1.5, bạn có thể trao đổi khá nhiều Integervới inttrong nhiều tình huống.

Tuy nhiên, tôi đã tìm thấy một khiếm khuyết tiềm năng trong mã của tôi làm tôi ngạc nhiên một chút.

Các mã sau đây:

Integer cdiCt = ...;
Integer cdsCt = ...;
...
if (cdiCt != null && cdsCt != null && cdiCt != cdsCt)
    mismatch = true;

dường như không chính xác khi đặt không khớp khi các giá trị bằng nhau, mặc dù tôi không thể xác định trong hoàn cảnh nào. Tôi đã đặt một điểm dừng trong Eclipse và thấy rằng các Integergiá trị đều là 137 và tôi đã kiểm tra biểu thức boolean và nó nói nó sai, nhưng khi tôi bước qua nó, nó đã đặt không khớp thành đúng.

Thay đổi điều kiện thành:

if (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt))

đã khắc phục sự cố.

Bất cứ ai có thể làm sáng tỏ tại sao điều này xảy ra? Cho đến nay, tôi chỉ thấy hành vi trên localhost của tôi trên PC của riêng tôi. Trong trường hợp cụ thể này, mã đã thành công vượt qua khoảng 20 so sánh, nhưng không thành công trên 2. Vấn đề là có thể lặp lại một cách nhất quán.

Nếu đó là một vấn đề phổ biến, thì nó sẽ gây ra lỗi trên các môi trường khác của chúng tôi (dev và test), nhưng cho đến nay, không ai báo cáo vấn đề này sau hàng trăm thử nghiệm thực thi đoạn mã này.

Nó vẫn không hợp pháp để sử dụng ==để so sánh hai Integergiá trị?

Ngoài tất cả các câu trả lời hay dưới đây, liên kết stackoverflow sau đây có khá nhiều thông tin bổ sung. Nó thực sự đã trả lời câu hỏi ban đầu của tôi, nhưng vì tôi không đề cập đến hộp thư tự động trong câu hỏi của mình, nên nó không hiển thị trong các đề xuất được chọn:

Tại sao trình biên dịch / JVM không thể tạo autoboxing chỉ hoạt động?

Câu trả lời:


238

JVM đang lưu các giá trị Integer. == chỉ hoạt động cho các số trong khoảng từ -128 đến 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


1
Cảm ơn, điều đó chắc chắn giải thích tại sao 137 thất bại! Và nó cũng trả lời câu hỏi của tôi về lý do tại sao nó không phải là vấn đề phổ biến, trong 95% các trường hợp tôi sẽ gặp phải, giá trị sẽ dưới 127. Tốt để nắm bắt điều này ngay bây giờ mặc dù 5% không xảy ra.
Jeremy Goodell

1
Lưu ý bên lề thú vị: cho đến vài tuần trước, cả cdiCt và cdsCt đều là ints nên điều này vẫn ổn, nhưng tôi phải làm cho họ các số nguyên để kiểm tra tình huống null được xử lý khác nhau ...
Jeremy Goodell

3
@Jeremy Vâng, đó là một vấn đề khá mơ hồ, nhưng như một quy tắc chung, bạn sử dụng .equals () cho các Đối tượng và == cho các nguyên thủy. Bạn không thể dựa vào autounboxing để kiểm tra tính bằng.
Adam

1
Lol, đánh dấu lại cho bạn rồi! Có vẻ như Colin đã có quá nhiều điểm rồi.
Jeremy Goodell

2
Lưu ý rằng Integer mới (1)! = Integer mới (1) là tốt. LUÔN LUÔN mới trả về một địa chỉ mới. Autoboxing sử dụng một phiên bản lưu trữ. Các cách khác trả về Số nguyên (không cần thêm chúng) có thể cũng trả về giá trị được lưu trong bộ nhớ cache.
Bill K

77

Bạn không thể so sánh hai Integervới một ==đối tượng đơn giản , vì vậy hầu hết các tài liệu tham khảo thời gian sẽ không giống nhau.

Có một mẹo, với Integerkhoảng từ -128 đến 127, các tham chiếu sẽ giống như sử dụng hộp thư tự động Integer.valueOf()lưu trữ các số nguyên nhỏ.

Nếu giá trị p được đóng hộp là true, false, byte, char trong phạm vi \ u0000 đến \ u007f hoặc số int hoặc short trong khoảng từ -128 đến 127, thì hãy để r1 và r2 là kết quả của bất kỳ hai chuyển đổi quyền anh nào của p. Luôn luôn là trường hợp r1 == r2.


Tài nguyên :

Cùng chủ đề:


1
Là sự đảm bảo từ JLS hay chỉ dành cho Oracle JVM?
Thorbjørn Ravn Andersen

Phần được trích dẫn là từ JLS, vì vậy đây là phần đảm bảo từ JLS
Colin Hebert

Re: đảm bảo. Tôi vẫn sẽ không dựa vào nó quá nhiều. new Integer(1) == new Integer(1)vẫn là sai
Thilo

@Thilo new ... == new ...luôn false.
MC Hoàng đế

2
@Thilo Đúng, luôn luôn sử dụng equals()khi tiếp xúc với đồ vật. Đây phải là một trong những điều đầu tiên người ta nên biết khi học Java. Nhân tiện, tôi đã đoán rằng hàm tạo của Integerlà riêng tư, tức là các thể hiện đó luôn được tạo thông qua valueOf()phương thức. Nhưng tôi thấy rằng các nhà xây dựng là công khai.
MC Hoàng đế

5

Vấn đề là hai đối tượng Integer của bạn chỉ là những đối tượng đó. Chúng không khớp bởi vì bạn đang so sánh hai tham chiếu đối tượng của mình, không phải các giá trị bên trong. Rõ ràng .equalslà bị ghi đè để cung cấp một so sánh giá trị trái ngược với so sánh tham chiếu đối tượng.


Câu trả lời hay, nhưng nó không giải thích được tại sao nó chỉ thất bại trong 137.
Jeremy Goodell

4

Integerđề cập đến tham chiếu, nghĩa là khi so sánh các tham chiếu bạn đang so sánh nếu chúng trỏ đến cùng một đối tượng, không phải giá trị. Do đó, vấn đề bạn đang thấy. Lý do nó hoạt động rất tốt với intcác loại đơn giản là vì nó bỏ hộp giá trị được chứa bởi Integer.

Tôi có thể thêm rằng nếu bạn đang làm những gì bạn đang làm, tại sao lại có iftuyên bố bắt đầu?

mismatch = ( cdiCt != null && cdsCt != null && !cdiCt.equals( cdsCt ) );

4

"==" luôn so sánh vị trí bộ nhớ hoặc tham chiếu đối tượng của các giá trị. Phương thức bằng luôn luôn so sánh các giá trị. Nhưng bằng nhau cũng gián tiếp sử dụng toán tử "==" để so sánh các giá trị.

Integer sử dụng bộ đệm Integer để lưu trữ các giá trị từ -128 đến +127. Nếu toán tử == được sử dụng để kiểm tra bất kỳ giá trị nào trong khoảng từ -128 đến 127 thì nó trả về giá trị true. đối với các giá trị khác, nó trả về false.

Tham khảo liên kết để biết thêm thông tin


0

Bên cạnh những câu trả lời tuyệt vời, những gì tôi đã học được là:

KHÔNG BAO GIỜ so sánh các đối tượng với == trừ khi bạn có ý định so sánh chúng bằng các tham chiếu của chúng.


0

Cũng như tính chính xác của việc sử dụng, ==bạn chỉ có thể bỏ hộp một trong các Integergiá trị được so sánh trước khi thực hiện ==so sánh, như:

if ( firstInteger.intValue() == secondInteger ) {..

Thứ hai sẽ được tự động mở hộp (tất nhiên bạn phải kiểm tra nulls trước).

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.