2013-09-11 15 views
6

Il seguente codice (Java) è legale?Quando è legale confrontare oggetti e primitive con l'operatore '=='?

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

Non verrà compilato rispetto a JDK 6 ma sembra bene su 7+. Le specifiche cambiano? È stato corretto un bug? Ho discusso al http://bugs.eclipse.org/bugs/show_bug.cgi?id=416950 e potrei andare in entrambi i modi su questo.

+2

controllare questo post precedente, [differenza di autoboxing java6 e java7] (http://stackoverflow.com/questions/16119638/differences-in-auto-unboxing-between-java-6-vs-java-7) – nachokk

risposta

1

Come risulta, è non legale per confrontare una primitiva con un'espressione di tipo "Object" in fase di compilazione. JLS 15.21 vieta espressamente:

Gli operatori di uguaglianza può essere utilizzata per confrontare due operandi pari convertibile (§5.1.8) di tipo numerico, o due operandi di tipo boolean o booleana, o due operandi che sono ciascuno di entrambi tipo di riferimento o il tipo null. Tutti gli altri casi generano un errore in fase di compilazione.

Il compilatore Eclipse segnala l'errore indipendentemente dalla versione di Java.Per Java 7, sia Oracle JDK che OpenJDK consentono erroneamente la compilazione del codice. Questo bug in Oracle e Open JDKs è corretto nella versione 8.

In sintesi, questo confronto vistoso è illegale in base alle specifiche e verrà compilato solo su alcuni sottoinsiemi di compilatori per un determinato sottoinsieme di obiettivi di versione lingua. Non funzionerà mai su Java 4- o 8+. Le conversioni di casting indicate in altre risposte si applicano solo all'operatore '=', non a '=='. 15.21.3 si applica solo a due operandi di riferimento.

0

Ecco il codice di byte di riferimento

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 
} 

Compilato con

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) 

Sembra essere la conversione del restituita String in un Boolean che ottiene unboxed.

3

JLS circa uguaglianza riferimento non cambia tra java 6 & 7:

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

Se gli operandi di un operatore di uguaglianza sono entrambi di entrambi riferimento tipo o del tipo nullo, l'operazione è l'uguaglianza degli oggetti.

Si tratta di un errore in fase di compilazione se è impossibile convertire il tipo di di un operando nel tipo dell'altro mediante una conversione di casting (§5.5). I valori di runtime dei due operandi sarebbero necessariamente non uguali.

Tuttavia ho notato alcune modifiche su Chapter 5.5: Casting Conversion. Casting booleano per oggetto sembra essere classificati come convenzione boxe il Java 7:

Espressione di un tipo primitivo può subire conversione colata a un tipo riferimento senza errori, mediante conversione boxe.

enter image description here

⊡ significa conversione boxe

Quindi dal momento che la primitiva true può essere colato a Object, la tua espressione uguaglianza può essere classificato come l'uguaglianza di riferimento su Java 7, e non cede errore di compilazione