So sánh các giá trị Dài được đóng hộp 127 và 128


110

Tôi muốn so sánh hai giá trị Long đối tượng bằng cách sử dụng các ifđiều kiện. Khi các giá trị này nhỏ hơn 128 , ifđiều kiện hoạt động bình thường, nhưng khi chúng lớn hơn hoặc bằng 128 , so sánh không thành công.

Thí dụ:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

So sánh trên mã ở trên hoạt động bình thường, nhưng không thành công trong mã dưới đây:

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

Tại sao có vấn đề trong việc so sánh các biến Long có giá trị lớn hơn 127 ? Nếu các kiểu dữ liệu biến được thay đổi thành nguyên thủy dài , thì so sánh sẽ hoạt động cho mọi trường hợp.

Câu trả lời:


212

TL; DR

Java lưu vào bộ đệm ẩn các phiên bản Integer từ -128đến 127. Vì bạn đang sử dụng ==để so sánh các tham chiếu đối tượng thay vì giá trị , nên chỉ các đối tượng được lưu trong bộ nhớ cache mới khớp. Làm việc với longcác giá trị nguyên thủy không được đóng hộp hoặc sử dụng .equals()để so sánh các Longđối tượng của bạn .

Phiên bản dài (dự định chơi chữ)

Tại sao có vấn đề khi so sánh biến Long với giá trị lớn hơn 127? Nếu kiểu dữ liệu của biến trên là nguyên thủy (dài) thì mã sẽ hoạt động với tất cả các giá trị.

Java lưu vào bộ nhớ cache các cá thể của đối tượng Số nguyên từ phạm vi -128 đến 127 . Mà nói:

  • Nếu bạn đặt giá trị là N biến Long 127(được lưu trong bộ nhớ cache ), thì cùng một đối tượng sẽ được trỏ tới bởi tất cả các tham chiếu. (N biến, 1 trường hợp)
  • Nếu bạn đặt giá trị là N Biến dài 128( không được lưu trong bộ nhớ cache ), bạn sẽ có một cá thể đối tượng được trỏ bởi mọi tham chiếu. (N biến, N phiên bản)

Đó là lý do tại sao điều này:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

Kết quả này:

đúng
sai

Đối với giá trị 127L , vì cả hai tham chiếu (val1 và val2) đều trỏ đến cùng một thể hiện đối tượng trong bộ nhớ (được lưu trong bộ nhớ đệm), nó sẽ trả về true.

Mặt khác, đối với giá trị 128 , vì không có phiên bản nào cho nó được lưu trong bộ nhớ, một phiên bản mới được tạo cho bất kỳ phép gán mới nào cho các giá trị được đóng hộp, dẫn đến hai phiên bản khác nhau (được trỏ bởi val3 và val4) và trả falsevề so sánh giữa chúng.

Điều đó chỉ xảy ra bởi vì bạn đang so sánh hai Long tham chiếu đối tượng , không phải longgiá trị nguyên thủy, với ==toán tử. Nếu không có cơ chế Cache này, các phép so sánh này sẽ luôn thất bại, vì vậy vấn đề thực sự ở đây là so sánh các giá trị được đóng hộp với ==toán tử.

Việc thay đổi các biến này thành kiểu nguyên thủy longsẽ ngăn điều này xảy ra, nhưng trong trường hợp bạn cần giữ mã của mình bằng cách sử dụng Longcác đối tượng, bạn có thể thực hiện các so sánh này một cách an toàn với các cách tiếp cận sau:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue());  // true
System.out.println((long)val3 == (long)val4);              // true

(Kiểm tra rỗng thích hợp là cần thiết, ngay cả đối với vật đúc)

IMO , luôn là một ý kiến ​​hay khi sử dụng các phương thức .equals () khi xử lý các phép so sánh Đối tượng.

Các liên kết tham khảo:


15

Java lưu trữ các giá trị nguyên thủy từ -128 đến 127 . Khi chúng ta so sánh hai đối tượng Long, java nội bộ gõ nó sang giá trị nguyên thủy và so sánh nó. Nhưng trên 127 đối tượng Long sẽ không nhận được kiểu đẳng cấp. Java lưu trữ kết quả đầu ra bằng phương thức .valueOf () .

Bộ nhớ đệm này hoạt động đối với Byte, Ngắn, Dài từ -128 đến 127. Đối với Bộ đệm số nguyên hoạt động Từ -128 đến java.lang.Integer.IntegerCache.high hoặc 127, tùy theo giá trị nào lớn hơn. (Chúng tôi có thể đặt giá trị cấp cao nhất cho đến giá trị Số nguyên sẽ được lưu vào bộ đệm bằng cách sử dụng java.lang.Integer.IntegerCache.high).

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

Đối tượng Float và Double không bao giờ được lưu vào bộ nhớ đệm.

Nhân vật sẽ nhận được bộ nhớ cache từ 0 đến 127

Bạn đang so sánh hai đối tượng. vì vậy toán tử == sẽ kiểm tra tính bình đẳng của các tham chiếu đối tượng. Có những cách sau để làm điều đó.

1) kiểu ép cả hai đối tượng thành các giá trị nguyên thủy và so sánh

    (long)val3 == (long)val4

2) đọc giá trị của đối tượng và so sánh

    val3.longValue() == val4.longValue()

3) Sử dụng phương thức equals () để so sánh đối tượng.

    val3.equals(val4);  

14

num1num2là các đối tượng Long. Bạn nên sử dụng equals()để so sánh chúng. ==so sánh đôi khi có thể hoạt động do cách đóng hộp JVM nguyên thủy, nhưng đừng phụ thuộc vào nó.

if (num1.equals(num1))
{
 //code
}

1
Điều này (tốt hơn) hoặc so sánh giá trị trả về của .longValue().
Giulio Franco

4

So sánh không nguyên thủy (hay còn gọi là Đối tượng) trong Java với ==so sánh tham chiếu của chúng thay vì giá trị của chúng. Longlà một lớp và do đó Longcác giá trị là Đối tượng.

Vấn đề là các Nhà phát triển Java muốn mọi người sử dụng Longgiống như họ đã từng sử dụng longđể cung cấp khả năng tương thích, dẫn đến khái niệm autoboxing, về cơ bản là một tính năng, long-giá trị sẽ được thay đổi thành Long-Objects và ngược lại khi cần thiết. Tuy nhiên, hoạt động của autoboxing không phải lúc nào cũng có thể dự đoán chính xác vì nó không được chỉ định hoàn toàn.

Vì vậy, để an toàn và có kết quả dự đoán, hãy luôn sử dụng .equals()để so sánh các đối tượng và không dựa vào hộp tự động trong trường hợp này:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
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.