Сравнение объекта и int в Java 7

Недавно я наткнулся на вопрос, который заставил меня остановиться и подумать...

Для меня приведенный ниже код всегда должен вызывать ошибку, но когда один из моих коллег спросил меня, почему Eclipse не показывает ее, я ничего не смог ответить.

class A {
    public static void main(String... args) {
        System.out.println(new Object() == 0);
    }
}

Я исследовал и обнаружил, что с уровнем исходного кода 1.6 действительно возникает ошибка:

incomparable types: Object and int

Но теперь в 1.7 компилируется нормально.

Пожалуйста, какая новая функция оправдывает такое поведение?


person rsalmei    schedule 29.08.2013    source источник


Ответы (1)


Что вы подразумеваете под «какая новая функция оправдывает такое поведение?» ? 1.7 исправляет проблему, присутствующую в 1.6. new Object() == 0 должен был никогда не вызывать ошибку и всегда вызывать срабатывание автоупаковки.

Просто не было причин, почему

Object a= 5 ;

было правильно, а не выражение

a == 3

или даже

a == 5

Это было крайне странно и, ИМХО, противоречило самой спецификации языка.

Однако с динамической точки зрения a == 5 по-прежнему оценивается как false, а (Integer)a == 5 или даже (int)a == 5 оценивается как true. Причина в том, что автораспаковка была разработана таким образом, чтобы никогда не создавать ClassCastExceptions, и, таким образом, происходит только для типов-оболочек, статически. Последние два случая являются явными приведениями типов, поэтому ClassCastException обычно разрешены.

person Mario Rossi    schedule 29.08.2013
comment
Вы имеете в виду, что теперь это эквивалентно new Object() == null и что new Object() == 2 по-прежнему вызывает ошибку? - person Martijn Courteaux; 29.08.2013
comment
Он должен быть более или менее эквивалентен new Object() == new Integer(0) (или new Integer(2)). Это никогда не должно быть ошибкой и всегда должно быть false, поскольку новый Object не может быть тем же объектом, что и объект Integer. - person ajb; 29.08.2013
comment
@MartijnCourteaux Не совсем так. Это эквивалентно new Object() == Integer.valueOf(0) и new Object() == Integer.valueOf(2). Оба всегда будут давать ложь, конечно. - person Mario Rossi; 29.08.2013
comment
Насколько я понимаю, технически это была ошибка версии 1.6. Но я думаю, что это вызовет больше проблем, потому что компилятор не предупредит вас, если вы случайно напишете что-то подобное, вместо того, чтобы иметь возможность написать a == 3. - person Martijn Courteaux; 29.08.2013
comment
Означает ли это, что в Object a = 10000; boolean b = a == 10000; b будет false? Потому что кеш Integer.valueOf достигает только 128. - person Martijn Courteaux; 29.08.2013
comment
@MartijnCourteaux Хороший вопрос. Компиляторы обычно выдают предупреждения для каждого автобокса, но многие отключают их чуть ли не по умолчанию, так что мы не могли на них рассчитывать. С другой стороны, вы можете сделать аналогичную ошибку со ссылками вместо чисел, а также это происходит только с классом Object (а может и Number). Учитывая, что дженерики почти полностью устранили (явное) использование Object, проблема может быть меньше, чем мы думаем. - person Mario Rossi; 29.08.2013
comment
@MartijnCourteaux Вы продолжаете делать хорошие выводы. Да: в Object a = 10000; boolean b = a == 10000; b будет ложным. Но в Integer a = 10000; boolean b = a == 10000; b было бы... правдой!!! (из-за правил автораспаковки). - person Mario Rossi; 29.08.2013
comment
В чем причина этого? Есть ли какой-нибудь раздел JLS об этом? - person Martijn Courteaux; 29.08.2013
comment
Извините, я сделал опечатку в моем первом ideone. Вот обновленная версия. Таким образом, это означает, что вместо автоматической упаковки в последнем случае этого теста происходит автоматическая распаковка: ideone.com/FSAWxe. - person Martijn Courteaux; 29.08.2013
comment
Джон Скит нашел ссылку на это поведение в JLS. Ознакомьтесь с его отличным ответом здесь: stackoverflow.com/a/1515811/155137. Теперь мне все ясно :) - person Martijn Courteaux; 29.08.2013
comment
@MartijnCourteaux Это обсуждение имеет незначительное отношение, поскольку оно относится к сравнениям обертки/оболочки и тому, как заставить их работать. Это всегда было очень ясно. Здесь речь идет об эталоне/примитиве. Специально Object/ примитивно. Упомянутые главы JLS, очевидно, связаны, потому что они посвящены преобразованиям и выражениям. - person Mario Rossi; 29.08.2013
comment
Да, я знаю. Я просто связал этот ответ из-за ссылок на JLS, которые он там разместил. Эти ссылки JLS объясняют, почему Integer i = 1000; boolean b = i == 1000; дает true. - person Martijn Courteaux; 29.08.2013
comment
@MartijnCourteaux Вы и Марио, спасибо за ваши комментарии, но я думаю, что это не совсем ответ на мой вопрос. Есть ли в Java 7 новая важная функция, которая поддерживает и объясняет такое поведение? Или это просто скрытое исправление? - person rsalmei; 24.09.2013
comment
похоже, что JDK 1.8.* снова рассматривает это как ошибку. (Лично я считаю, что это хорошо — такой код в любом случае сильно пахнет) - person Display Name; 26.02.2015
comment
Хорошо спроектированный язык позволяет применять определенные преобразования типов в одних контекстах, но запрещает их в других. Упрощенное представление о том, что преобразования типов, которые применимы везде, должны быть применимы везде, означает, что double a=1234567890/10.0f; молча даст 123456792.0, а не потребует от программиста более утвердительного указания того, что на самом деле предназначено. Принятие представления о том, что такие операторы, как ==, должны быть более разборчивыми, чем некоторые другие, сделает практичным использование правил преобразования, которые намного полезнее, чем правила, которые должны применяться везде. - person supercat; 18.09.2015