2014-10-30 13 views
5

Ho scoperto che in Eclipse (utilizzando il compilatore Eclipse) posso utilizzare alcune funzionalità del linguaggio Java 7, ma comunque creare file di classe Java 6. Nell'immagine sottostante, è possibile visualizzare due funzionalità del linguaggio Java 7 che vengono compilate correttamente come file di classe Java 6. Tuttavia, altre funzionalità di Java 7, quelle commentate, non vengono compilate.Perché Eclipse mi consente di compilare alcune funzionalità del linguaggio Java 7 in file di classe Java 6?

La mia ipotesi è che Eclipse stia determinando quali funzionalità del linguaggio Java 7 sono compatibili con Java 6 JVM e quali no. Ad esempio, il tipo generico JComboBox è solo una funzionalità di compilazione (e non di runtime), quindi posso immaginare come sarebbe compatibile. La funzione di interruttore String se penserei potrebbe fare differenze nel codice di byte e contare su nuove funzionalità di JVM, ma potrei sbagliarmi ...

Le mie domande:

  • è Eclipse davvero abbastanza intelligente da sapere quali funzionalità di Java 7 linguaggio sono in grado di essere compilate in file di classe Java 6 e quali no?

  • L'esempio seguente chiaramente non è compatibile con la sorgente di 1,6, quindi perché l'impostazione di "Compatibilità origine" su 1,6 non causa un errore?

  • Questo "trucco" sembra consentirmi di utilizzare almeno alcune funzionalità del linguaggio Java 7 e di creare ancora file di classe Java 6. L'utilizzo di javac con source 1.7 e target 1.6 fallirebbe, quindi perché funziona? Il compilatore Ecilpse ha una caratteristica che javac non possiede?

enter image description here

Per motivi di confronto qui è il risultato quando passo a un Java 6 compilatore, come previsto.

enter image description here

risposta

0

mia ipotesi è che ha ragione sul perché CGE compilerà quarantina e non altri quando è impostata su Java 6. Generics non basta compilare verso il basso per le stesse cose come proietta quindi che potrebbe essere il motivo per cui funziona se il target è impostato su java 6?

Vedere What is the difference between javac and the Eclipse compiler? per le altre differenze tra javac ed ECJ.

1

Penso due cose stanno accadendo:

  1. ho il sospetto che la prima linea (con generici JComboBox) funziona perché il Java 1.7 rt.jar è legato al posto di Java 1.6 rt.jar (Ho un progetto che è di installazione con JavaSE-1.6, e in tal caso, quella prima riga non viene compilata nemmeno con la prima combinazione di impostazioni). Ma questo è un problema di libreria di classi, non un problema di versione linguistica. (È possibile ottenere un sacco di problemi anche con javac se si compila l'app Java contro un nuovo rt.jar rispetto a quando lo si esegue).

  2. La seconda riga rappresenta probabilmente un bug nel compilatore Eclipse. Mentre la maggior parte delle nuove funzionalità del linguaggio Java 7 può essere implementata esclusivamente nel compilatore (che fa Android dalla fine del 2013), farlo ovviamente non è compatibile con la sorgente Java 6.

Così, in breve, avete trovato almeno un bug in un (probabilmente) configurazione insolita Eclipse. Abbi cura di te e non fare affidamento su di esso.

0

Ciò potrebbe essere dovuto alla libreria di sistema JRE configurata nel percorso di generazione del progetto che non corrisponde al livello di conformità che hai selezionato. In generale, quasi sempre si desidera selezionare l'opzione "Utilizza conformità dall'ambiente di esecuzione" nelle impostazioni del compilatore del progetto. Controlla il percorso di creazione del tuo progetto e verifica se hai specificato la libreria di sistema JRE come ambiente di esecuzione.

1

Non so perché Eclipse consente questo o se si tratta solo di un bug. 1.7 javac vi dirà che

error: strings in switch are not supported in -source 1.6 

anche io non so perché JComboBox opere,

System.out.println(new JComboBox<String>() {}.getClass().getGenericSuperclass()); 

> javax.swing.JComboBox<java.lang.String> 

ha informazioni generiche in fase di esecuzione, che non dovrebbe essere lì. Consentire l'uso di generici per classi che non sono generiche dovrebbe IMO essere respinto come incompatibile. Tuttavia non ho eseguito il codice sopra JVM6. Forse si romperà anche.

Ma almeno lo switch non è tecnicamente un problema. http://www.benf.org/other/cfr/java7switchonstring.html mostra che questo è solo un trucco del compilatore che non richiede nuove funzionalità linguistiche, API o bytecode.

esempio leggermente semplificata:

int java7(String string) { 
    switch (string) { 
     case "BB": 
      return 12; 
     case "FRED": 
      return 13; 
    } 
    return 0; 
} 

diventa essenzialmente

int java6(String string) { 
    switch (string.hashCode()) { 
     case 2112: 
      if (string.equals("BB")) 
       return 12; 
      break; 
     case 2166379: 
      if (string.equals("FRED")) 
       return 13; 
      break; 
    } 
    return 0; 
} 

che si basa sul fatto che l'esito del String#hashCode() è specificato e non deve cambiare. Il compilatore ti risparmia solo un po 'di tempo per scrivere codice legale altrimenti più veloce.

Lo stesso dovrebbe valere per l'operatore di diamanti: ad es. new ArrayList<>() può essere semplicemente risolto dal compilatore.

Gli strumenti Android, che consentono la stessa semi 7 compatibilità, consentono di utilizzarlo. Tuttavia, la differenza è che utilizzano file .class destinati a Java 7. Android ha comunque bisogno di convertire file .class nel suo formato interno, quindi il loro compilatore da .class a .dex può usare qualsiasi input per generare istruzioni comprese dal runtime Android.

try-with-risorsa per esempio, non funziona in quanto richiede tra gli altri l'interfaccia AutoCloseable con non esisteva in Java 6.

e funzioni speciali come le espressioni lambda non richiedere nuovi tipi di bytecode pure.

Problemi correlati