Чому (i <= j && j <= i && i! = J) оцінюється ІСТИНА?


104

Я написав фрагмент коду Java, який працює в нескінченному циклі.

Нижче наведено код:

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);
        }
    }
}

У наведеному вище коді, побачивши умову в whileциклі, спочатку схоже, що програма не піде всередину whileциклу. Але насправді це нескінченний цикл і продовжує друкувати значення.

Що тут відбувається?


8
Проста відповідь - i<=j && j<=i && i!=jце умова завжди оцінюється як істинна. Просто візьміть аркуш паперу і оцініть, що його зловить :)
Pradeep Simha

4
Неправильний спосіб створення цілого числа. Використовувати "
порівняти до

7
Якщо ви ніколи не змінюєтесь, iабо j, коли ви очікуєте, що цикл припиниться?
Фред Ларсон

33
@PradeepSimha Для простих значень INT, то це завжди дає БРЕХНЯ . З i<=jі j<=iможна зробити висновок про те i == j, що суперечить останньому терміну. Таким чином, весь вираз оцінюється як хибний, а час не вводиться. Ключовий момент - тут ідентичність об'єкта!
Сірко

4
На відміну це головоломка 32 у книзі Язикові загадки: пастки, підводні камені та кутові випадки.
Cyanfish

Відповіді:


188
  • i <= jоцінюється в true, так як авто розпакування відбувається за ІНТ порівнянь , а потім , як iі jутримувати значення за замовчуванням 0.

  • j <= iоцінюється trueчерез вищезазначену причину.

  • i != jоцінюється на true, тому що обидва iі jє різними об'єктами. І порівнюючи об'єкти, немає необхідності в автоматичному розпакуванні.

Усі умови справжні, і ви не змінюєтесь iі jв циклі, тому він працює нескінченно.


10
Ви можете пояснити, чому! = це перевірка на індекс пам'яті референтних об'єктів і <= перевірка на небілеве значення Integer ?? .. чому між цими операторами існує така різниця?
Punith Raj

41
@PunithRaj <&> оператори працюють на примітивах, а не на об'єктах, отже, автоматичне розпакування відбувається для цих операторів. Але для порівняння об'єктів також можна використовувати оператори == і! =, Тому тут не потрібно розпаковувати, тому об'єкти порівнюються.
Juned Ahsan

14
Ах, приховані небезпеки неявного боксу / розпакування !!
Гарячі лизи

3
Переповнення стека повинно просто додати новий тег: "Авторозпакування було найбільшою помилкою, що коли-небудь робилася в Java". :-). За винятком письменників книг Java Puzzler. Використовуйте його для позначення таких питань.
user949300

4
зауважте, що Integer.valueOf(0) == Integer.valueOf(0)завжди оцінюється як істинне, тому що в цьому випадку повертається той самий об’єкт (див. IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… )
Віталій Федоренко

40

Тому що ти порівнюєш

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)як ви створюєте об'єкти, а не примітивне порівняння. Так воно оцінює до while(true) { // Never ending loop }.


2
Ох! прихований Дракон авто БЕЗКОШТОВНО ... Добре пояснення.
HybrisHelp

17

Цілі об'єкти різні. Він відрізняється від основного типу int.

Дивіться цю відповідь: Як правильно порівняти два цілих числа на Java?

i != jЧастина правди, що ви очікували помилкові.


Незважаючи на те, що це правда, це не має значення і не відповідає на питання.
Кон,

6
@Kon: Насправді це відповідь. Умови №1 та №2 визначаються trueчерез автобоксинг. У випадку №3 автобоксинг не застосовується, а порівняння відбувається на рівні об'єкта (пам'яті).
додому

1

Цикл не закінчується, тому що ваша умова є істинним (i! = J є істинним, оскільки є 2 різні об'єкти, використовуйте замість Integer.valueOf), а всередині циклу значення не змінюються, тому ваш стан залишається вірним назавжди.


1

Цілі об'єкти різні. Він відрізняється від основного типу int. тож ви можете просто так зробити. що ти робиш, це просто порівняти об’єкт, і звичайно результат справжній.


1

Є два різні випадки, які ми маємо розібратися спочатку,

випадок 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);

випадок 2:

        Integer i = 10;
        Integer j = 10;

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

обидва різні, як

у випадку 1: i!=jце буде trueтому, що обидва посилання на два різні об’єкти в купі і не можуть бути однаковими. Але

у випадку 2: i==jбуде trueтому, що обидва 10 є цілими літералами, а Java підтримує pool for Integer literalsзначення, які мають значення (-128 <= X <= 127). Отже, у цьому випадку 10 <= 127 результатів відповідають дійсності, тож обидва матимуть посилання на один і той же об’єкт.


0

Можливо, причина полягає в тому, що і 'i', і 'j' є об'єктами, а порівняння об'єктів - це не те саме, що порівняння посилань на об'єкти. Будь ласка, подумайте про використання! I.equals (j) замість i! = J


0

Програма продовжує відображати однакове значення , iтому що ви не збільшуючи або зменшуючи або значення iабо j. Умова у програмі for завжди продовжує оцінювати як істину, тому це нескінченна петля.


Я думаю, що питання стосувалося більше тієї i!=jчастини, яка дивно оцінює справжню, а не <=порівняння.
Soravux

0

Integer a = новий цілий (0); Цілий b = новий цілий (0);

Порівняння <= і> = використовуватиме нерозмітне значення 0, тоді як! = Порівняє посилання та матиме успіх, оскільки вони є різними об'єктами.

Навіть це також працює i, e

Ціле число a = 1000; Ціле число b = 1000;

але це не так:

Ціле число a = 100; Ціле число b = 100;

Причина полягає в тому, що Integer внутрішньо використовує кешування об'єктів Integer між -128 і 127 і повертає екземпляри з цього кеша для діапазону, який він охоплює. Я не впевнений, але, мабуть, ви також можете змінити його максимальне значення в пакеті "java.lang.Integer.IntegerCache.high".

Для кращого розуміння перевірте URL-адресу: https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


-3

ви повинні знати його дещо інше в && це, і це & коли ви використовуєте &&, то коли перша умова є вірною, то вона перевіряє друге умова, якщо його невірно, то не перевіряється третьою умовою, оскільки в & операторі, якщо одна умова помилкова оператор хибний, якщо використовується || тоді, якщо він бачить істину, то він повертає істину у вашому коді, тому що i і j рівні перші та другі умови є істинними, тоді в третьому умові вони будуть помилковими, оскільки вони рівні, а умова - хибною.


я не знаю , чому моя відповідь отримати значення рудників , тому що моя відповідь вірно бачити це посилання це правда , то , перш ніж отримати хв до моєї відповіді читати далі stackoverflow.com/questions/5564410/difference-between-and
сара Sodagari
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.