Можно ли сравнить равенство `boolean` и` Object`?

Следующий код

public class TestComparison {
    public static void main(String[] args) throws Exception {
        boolean b = true;
        Object o = new Boolean(true);
        System.out.println("comparison result: "+ 
            (o == b)); // Eclipse complains about this expression
    }
}

компилируется без ошибок с javac V1.7.0_15 и печатает "false" при запуске. Тем не менее, Eclipse Juno жалуется на "Несовместимые типы операндов Object и boolean".

Очевидно, javac autoboxes примитивный логический b, а затем сравнивает o и autoboxed b по равенству объекта, давая false, в то время как Eclipse отказывается делать автобоксинг.

Какое правильное поведение соответствует спецификации языка Java? Где я должен указать ошибку?

Примечание. Если я изменяю тип o на Boolean, все работает так, как ожидалось: Eclipse принимает код, а код печатает "true".

Runnable version на ideone.com

Ответ 1

Это ваш уровень языкового уровня вашего проекта. Вероятно, вы используете компилятор Java 7 с семантикой Java 6. У меня нет Eclipse здесь, но я воспроизвел его в IntelliJ, который дал ошибки, когда языковой уровень был на Java 6, хотя я использовал компилятор 7. Я думаю, что Eclipse имеет то же самое. Эта ссылка объясняет это.

Ответ 2

Относительно вашего "примечания", что код компилируется и работает, когда o изменен на Boolean:

Этот код:

public class Tester{
  public static void main(String args[]){
    Boolean one = new Boolean(true);
    Object two = new Boolean(true);
    boolean three = true;
    System.out.println("SAME 1:2 " + (one == two) + " 1:3 " + (one == three) + " 2:3 " + (two == three));
    System.out.println("EQUAL 1:2 " + (one.equals(two)) + " 1:3 " + (one.equals(three)) + " 2:3 " + (two.equals(three)));
  }
}

производит этот результат:

SAME 1:2 false 1:3 true 2:3 false
EQUAL 1:2 true 1:3 true 2:3 true

Чтобы понять, почему это так, нам нужно рассмотреть типы времени компиляции различных выражений:

  • one == two сравнивает Boolean с Object - это оба ссылочных типа, поэтому тест является ссылочным равенством (Спецификация Java Language, Java SE 7 edition, §15.21.3)
  • one == three сравнивает a Boolean с Boolean - это рассматривается как сравнение примитивных значений Boolean (§15.21.2); one распаковывается и сравнивается с three.
  • two == three сравнивает Object с Boolean - в этом случае Boolean преобразуется в Object с помощью преобразования каста (§5.5, в этом случае бокс Boolean до Boolean, а затем расширение Boolean до Object), а затем два сравниваются для ссылочного равенства.

Строка EQUAL намного проще - все три случая являются вызовами Boolean.equals(Object other), используя бокс, когда аргумент three.