2012-01-29 15 views
21

Trovato cosa interessante mentre compilare il seguente pezzo di codice:foreach con nome variabile pari al nome del campo

1 class A { 
2   
3  private B line; 
4 
5  public void foo() { 
6  for (Integer line : line.getElements()) { 
7  
8  } 
9  } 
10 } 
11  
12 class B { 
13  
14  List<Integer> getElements() { 
15   return null; // doesn't matter 
16  } 
17 } 

Prestare attenzione alla Linea 6: si vede che il nome della variabile è uguale al nome del campo. IntelliJ Idea 11 lo ignora e pensa che qui non ci siano problemi. Ma il compilatore java mi dice che 'line non ha metodo getElements'. Quindi, due domande:

  1. Devo inviare una segnalazione di errore in Idea?
  2. Perché il messaggio di errore di Java è simile a questo? Non è in grado di rilevare l'errore? Che meccanismo funziona qui? Eclipse di variabile di campo?
+1

Il comportamento Idea IntelliJ deve essere coerente con il compilatore javac. – dcernahoschi

risposta

13

Questo potrebbe essere un bug nel compilatore Java che si sta utilizzando. In base allo Java Language Specification (section 14.14.2), l'ambito della variabile in un'istruzione for avanzata è l'istruzione contenuta. (Ciò sembra escludere l'espressione iterabile o di matrice alla destra di :.)

È possibile aggirare il problema utilizzando this.line.getElements().

EDIT Solo per i calci, ho presentato questo come un bug report a Sun. Vedremo se gli ingegneri Java pensano che sia un bug nel JLS o in javac (o se hanno qualche altra spiegazione). L'ID del bug è 7139681, anche se non verrà pubblicato nel database esterno per un paio di giorni.

+0

@Tedd: puoi elaborare una "dichiarazione contenuta"? – kosa

+0

Non sono sicuro che la specifica lo dica. "L'ambito di una variabile locale dichiarata nella parte FormalParameter di un'istruzione enhanced for (§14.14) è l'istruzione contenuta" - problema: non esiste una parte "FormalParameter" in una versione migliorata per AFAICT. – Mat

+0

@ Mat, le specifiche lo dicono e anch'io sono confuso. – kosa

7

Se si dichiara variabile locale (che è ciò che si è fatto) con lo stesso nome di campo, allora è possibile accedere alla variabile di campo come this.name.

for (Integer line : this.line.getElements()) { 
} 
+6

[Sezione 14.14.2 delle specifiche della lingua Java] (http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.14.2) sembra suggerire che l'ambito del locale variabile è solo l'istruzione racchiusa (la parte tra '{}'), e non include l'espressione tra parentesi alla destra di ':'. –

-2

Quando si utilizza IntelliJ, esso analizza automaticamente tutti i file. Tuttavia con javac potrebbe non compilare tutti i programmi, specialmente se sono stati compilati in precedenza.

Supponiamo di avere una classe B (senza getElements()) e la si compila. Più tardi si aggiunge il metodo e si compila solo A, si lamenterà che B non ha quel metodo perché l'ultima volta che lo hai compilato, non esisteva un tale metodo.

Per ovviare a questo è necessario eliminare tutti i file * .class prima di compilare o utilizzare uno strumento di generazione come Maven.

+1

Non è il caso. Ho fatto una ricostruzione pulita e completa. nessun effetto. –

+2

Questo non ha nulla a che fare con la domanda di OP. Il problema può essere ridotto a una singola classe: 'Bug di classe pubblica { \t int [] indice; \t pubblico bug void() { \t \t for (int index: index) { \t \t} \t}} ' –

+0

Mi dispiace, ho perso l'errore intenzionale nel codice. ;) –