2013-09-11 3 views
6

Является ли код ниже (Java) законным?Когда законно сравнивать объекты и примитивы с оператором '=='?

class Test { 
    Object foo() {return "";} 
    boolean bar() {return foo() == true;} 
} 

Он не будет скомпилирован против JDK 6, но, похоже, на 7+. Изменена ли спецификация? Исправлена ​​ли ошибка? Я обсуждал в http://bugs.eclipse.org/bugs/show_bug.cgi?id=416950 и мог пойти в любом случае на этом.

+2

проверьте этот предыдущий пост, [разница в autoboxing java6 и java7] (http://stackoverflow.com/questions/16119638/differences-in-auto-unboxing-between-java-6-vs-java-7) – nachokk

ответ

1

Как выясняется, это не законно сравнить примитив с выражением типа времени компиляции «Объект». JLS 15.21 прямо запрещает это:

Операторы равенства может быть использован для сравнения двух операндов, которые являются складными (§5.1.8) для числового типа, или два операнда типа булевой или Boolean, или два операнда, которые каждый из либо ссылочный тип или нулевой тип. Все остальные случаи приводят к ошибке времени компиляции.

Компилятор Eclipse отмечает ошибку независимо от версии Java.Для Java 7 оба Oracle JDK и OpenJDK ошибочно позволяют компилировать код. Этот bug в Oracle и Open JDKs исправлен в версии 8.

Таким образом, это неудобное сравнение является незаконным в соответствии со спецификацией и будет компилироваться только на некоторых подмножествах компиляторов для определенного подмножества целей языковой версии. Никогда не будет работать на Java 4- или 8+. Кастинговые преобразования, упомянутые в других ответах, применимы только к оператору '=', а не к '=='. 15.21.3 применяется только к двум опорным операндам.

0

Вот байт-код для справки

class Test { 
    Test(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>": 
     4: return 

    java.lang.Object foo(); 
    Code: 
     0: ldc   #2     // String 
     2: areturn 

    boolean bar(); 
    Code: 
     0: aload_0 
     1: invokevirtual #3     // Method foo:()Ljava/lang/Object; 
     4: iconst_1 
     5: invokestatic #4     // Method java/lang/Boolean.valueOf: 
     8: if_acmpne  15 
     11: iconst_1 
     12: goto   16 
     15: iconst_0 
     16: ireturn 
} 

Собран с

java version "1.7.0_25" 
Java(TM) SE Runtime Environment (build 1.7.0_25-b17) 
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode) 

Это, кажется, преобразования возвращенного String в Boolean, который получает распакованный.

3

ПСБ о равенстве эталонного не изменяется между Java 6 & 7:

Chapter 15.21.3: Reference Equality Operators == and !=:

Если операнды операции равенства являются либо эталонного типа или нулевой типа, то операция является равенством объекта.

Это ошибка времени компиляции, если невозможно преобразовать тип либо в операнд по типу другого путем преобразования отливки (§5.5). Значения времени выполнения двух операндов обязательно равны .

Однако я заметил некоторое изменение на Chapter 5.5: Casting Conversion. Отливки логического значения, чтобы объект появляется, чтобы быть классифицировано как бокс конвенция о Java 7:

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

enter image description here

⊡ означает преобразование бокса

Следовательно, так как примитивный true может быть преобразован в Object, ваше выражение равенства может быть классифицировано как равенство ссылок на Java 7, и не приводит к ошибке компилятора

Смежные вопросы