Tại sao (i <= j && j <= i && i! = J) đánh giá là ĐÚNG?


104

Tôi đã viết một đoạn mã Java đang chạy trong một vòng lặp vô hạn.

Dưới đây là mã:

public class TestProgram {
    public static void main(String[] args){
        Integer i = new Integer(0);
        Integer j = new Integer(0);

        while(i<=j && j<=i && i!=j){
            System.out.println(i);
        }
    }
}

Trong đoạn mã trên, trong khi nhìn thấy điều kiện trong whilevòng lặp, thoạt đầu có vẻ như chương trình đó sẽ không đi vào bên trong whilevòng lặp. Nhưng thực ra nó là một vòng lặp vô hạn và tiếp tục in giá trị.

Chuyện gì đang xảy ra ở đây?


8
Câu trả lời đơn giản là i<=j && j<=i && i!=jđiều kiện này luôn luôn đánh giá là đúng. Chỉ cần lấy một mảnh giấy và đánh giá bạn sẽ bắt nó :)
Pradeep Simha

4
Cách bạn đang tạo số nguyên không chính xác. Sử dụng '
CompareTo

7
Nếu bạn không bao giờ thay đổi ihoặc j, khi nào bạn mong đợi vòng lặp kết thúc?
Fred Larson

33
@PradeepSimha Đối với các giá trị int đơn giản, điều này sẽ luôn mang lại giá trị false . Từ đó i<=jj<=ibạn có thể kết luận, điều i == jđó mâu thuẫn với thuật ngữ trước. Do đó, toàn bộ biểu thức được đánh giá là false và while sẽ không được nhập. Điểm mấu chốt là nhận dạng đối tượng ở đây!
Sirko

4
Ngoài ra, đây là câu đố 32 trong cuốn sách Câu đố Java: Bẫy, Cạm bẫy và Vụ án góc.
Cyanfish

Câu trả lời:


188
  • i <= jđược đánh giá là truevì tự động mở hộp xảy ra đối với các so sánh int và sau đó là cả hai ijgiữ giá trị mặc định 0,.

  • j <= iđược đánh giá là truevì lý do trên.

  • i != jđược đánh giá truevì cả hai ijđều là các đối tượng khác nhau. Và trong khi so sánh các đối tượng, không cần phải tự động mở hộp.

Tất cả các điều kiện đều đúng, và bạn không thay đổi ijtrong vòng lặp, vì vậy nó đang chạy vô hạn.


10
bạn có thể vui lòng giải thích, tại sao! = đang kiểm tra chỉ số bộ nhớ của các đối tượng tham chiếu và <= đang kiểm tra giá trị không được đóng hộp của Integer ?? .. tại sao lại có sự khác biệt giữa các toán tử này?
Punith Raj 14/09/13

41
Các toán tử @PunithRaj <&> hoạt động trên nguyên thủy chứ không phải trên các đối tượng, do đó việc tự động mở hộp xảy ra đối với các toán tử này. Nhưng các toán tử == và! = Cũng có thể được sử dụng để so sánh các đối tượng vì vậy không cần mở hộp ở đây, do đó các đối tượng được so sánh.
Juned Ahsan 14/09/13

14
Ah, những nguy cơ tiềm ẩn của quyền anh / unboxing tiềm ẩn !!
Hot Licks

3
Stack Overflow chỉ nên thêm một thẻ mới, "Tự động mở hộp là lỗi lớn nhất từng mắc phải trong Java". :-). Ngoại trừ những người viết sách Java Puzzler. Sử dụng nó để gắn thẻ những câu hỏi như thế này.
user949300 15/09/13

4
lưu ý rằng Integer.valueOf(0) == Integer.valueOf(0)luôn được đánh giá là true vì trong trường hợp này, cùng một đối tượng được trả về (xem IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… )
Vitalii Fedorenko

40

Bởi vì bạn đang so sánh

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)khi bạn đang tạo các đối tượng, không phải so sánh ban đầu. Vì vậy, nó đánh giá while(true) { // Never ending loop }.


2
Ồ! Rồng ẩn của auto UNBOXING ... Giải thích hay.
HybrisHelp

17

Các đối tượng số nguyên là khác nhau. Nó khác với kiểu int cơ bản.

Xem câu trả lời này: Làm thế nào để so sánh đúng hai số nguyên trong Java?

Phần i != jđúng, phần mà bạn mong đợi là sai.


Mặc dù đúng, nó không quan trọng ở đây cũng như không trả lời câu hỏi.
Kon

6
@Kon: Thực tế đây là câu trả lời. Điều kiện số 1 và số 2 đánh giá là truedo tính năng tự động đóng hộp. Trong trường hợp # 3 autoboxing không áp dụng và so sánh diễn ra ở cấp đối tượng (vị trí bộ nhớ).
nhà

1

Vòng lặp không kết thúc vì điều kiện của bạn là đúng (i! = J là đúng vì có 2 đối tượng khác nhau, hãy sử dụng Integer.valueOf thay thế) và bên trong vòng lặp, các giá trị không thay đổi nên điều kiện của bạn vẫn đúng mãi mãi.


1

Các đối tượng số nguyên là khác nhau. Nó khác với kiểu int cơ bản. vì vậy bạn có thể làm như vậy. những gì bạn làm chỉ là so sánh đối tượng và tất nhiên kết quả là đúng.


1

Có hai trường hợp khác nhau mà chúng ta phải hiểu trước,

trường hợp 1:

        Integer i = new Integer(10);
        Integer j = new Integer(10);

        System.out.println((i<=j && j<=i && i!=j));
        System.out.println(i!=j);

trường hợp 2:

        Integer i = 10;
        Integer j = 10;

        System.out.println((i<=j && j<=i && i==j));
        System.out.println(i==j);

cả hai đều khác nhau, như

trong trường hợp 1: i!=jsẽ là truedo cả hai đều tham chiếu đến hai đối tượng khác nhau trong heap và không thể giống nhau. Nhưng

trong trường hợp 2: i==jsẽ là truevì cả 10 đều là các ký tự nguyên và Java duy trì các ký tự pool for Integer literalsnày có giá trị (-128 <= X <= 127). Vì vậy, trong trường hợp này 10 <= 127 kết quả là true, Vì vậy, cả hai sẽ có tham chiếu đến cùng một đối tượng.


0

Có lẽ lý do là cả 'i' và 'j' đều là đối tượng, và so sánh đối tượng không giống như so sánh tham chiếu đối tượng. Hãy cân nhắc sử dụng! I.equals (j) thay vì i! = J


0

Chương trình tiếp tục hiển thị cùng một giá trị của ivì bạn không tăng hoặc giảm giá trị của ihoặc j. Điều kiện trong for luôn luôn đánh giá thành true, vì vậy nó là một vòng lặp vô hạn.


Tôi nghĩ câu hỏi thiên về i!=jphần đánh giá đáng ngạc nhiên là đúng chứ không phải <=so sánh.
Soravux

0

Integer a = new Integer (0); Integer b = new Integer (0);

Các phép so sánh <= và> = sẽ sử dụng giá trị 0 được mở hộp, trong khi! = Sẽ so sánh các tham chiếu và sẽ thành công vì chúng là các đối tượng khác nhau.

Ngay cả điều này cũng sẽ hoạt động tôi, e

Số nguyên a = 1000; Số nguyên b = 1000;

nhưng điều này không:

Số nguyên a = 100; Số nguyên b = 100;

Lý do là vì Integer sử dụng bộ nhớ đệm bên trong cho các đối tượng Integer giữa -128 và 127 và trả về các thể hiện từ bộ đệm đó cho phạm vi mà nó bao gồm. Tôi không chắc nhưng tôi đoán bạn cũng có thể thay đổi giá trị tối đa của nó trong gói "java.lang.Integer.IntegerCache.high".

Để hiểu rõ hơn, hãy kiểm tra url: https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


-3

bạn phải biết nó hơi khác một chút trong && cái này và cái này & khi bạn sử dụng && thì khi điều kiện đầu tiên là đúng thì nó sẽ kiểm tra điều kiện thứ hai nếu nó sai thì nó không kiểm tra điều kiện thứ ba vì trong toán tử & nếu một điều kiện là sai thì tất cả câu lệnh sai nếu sử dụng || sau đó nếu nó thấy true thì nó trả về true trong mã của bạn vì i và j là bằng nhau và điều kiện thứ nhất là true thì ở điều kiện thứ ba nó sẽ là false vì chúng bằng nhau và while điều kiện là false.


tôi không biết lý do tại sao câu trả lời của tôi nhận được giá trị mỏ vì câu trả lời của tôi là đúng sự thật xem liên kết này nó đúng thì trước khi có được mỏ vào câu trả lời của tôi đọc thêm stackoverflow.com/questions/5564410/difference-between-and
sara Sodagari
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.