2014-11-06 14 views
5

Per distinguere tra un campo di istanza e una variabile locale con lo stesso nome che possiamo qualificare l'accesso al campo con il prefisso this.:Assegnare al campo finale statico del omonimo

class Test { 
    public final Foo x; 

    public Test(Foo x) { 
     this.x = x; 
    } 
} 

che sto cercando di fare la stessa cosa in un contesto statico qualificando l'accesso con il nome della classe:

import java.util.*; 

class Test { 
    public static final Map<String,Object> map; 

    static { 
     Map<String,Object> map = new HashMap<>(); 

     // ... 
     // assume I fill the map with useful data here 
     // ... 

     // now I want to freeze it and assign it to the field 
     Test.map = Collections.unmodifiableMap(map); 
    } 
} 

il compilatore non vuole avere niente a che fare con questo codice. Ho diverse variabili come questa e per tutte loro continua a urlare: "non posso assegnare un valore alla variabile finale". Se I non lo assegna a, si lamenta invece "variabile non inizializzata". Se assegno il campo statico all'inizio e cerco di rendere la mappa non modificabile in seguito, si lamenta che "la variabile potrebbe essere già stata assegnata". Non è contento di nulla.

È un difetto nella lingua o un errore nel compilatore? Qual è il modo migliore per fare in modo che il compilatore si comporti nel modo in cui viene detto?

+1

Utilizzare due nomi diversi. Non c'è motivo per cui la 'map' all'interno del blocco statico debba avere lo stesso nome del campo' map' statico. – ajb

+0

Rinominare funziona, ma è brutto, perché uso le variabili più volte nel blocco di inizializzazione e sarebbero più significativi con i loro nomi propri. Mi stavo chiedendo se ci fosse qualcosa di meglio. – Boann

risposta

5

Il modo più semplice di risolvere è la seguente:

import java.util.*; 

class Test { 
    public static final Map<String,Object> map; 

    static { 
     Map<String,Object> contents = new HashMap<>(); 

     map = Collections.unmodifiableMap(contents); 
    } 
} 

In qualche modo sembra che se si qualificano la costante con il nome della classe in Java 8, il compilatore non averlo.

Aggiornamento

Dopo un po 'di più di scavo, sembra che il Java Language Specification afferma esplicitamente che la semplice (non qualificato) nome deve essere utilizzato per l'assegnazione dei campi finali (evidenziando miniera):

Per ogni accesso di una variabile locale o di un campo finale vuoto x, x deve essere assegnato definitivamente prima dell'accesso oppure si verifica un errore di compilazione.

Analogamente, ogni variabile finale vuota deve essere assegnata al massimo una volta; deve essere definitivamente non assegnato quando si verifica un incarico.

Tale assegnazione è definito verificarsi se e solo se sia il semplice nome della variabile (o, per un campo, la sua semplice nome qualificato da questo) si verifica sul lato sinistro di un'assegnazione operatore.

+1

Grazie per averlo rintracciato nel JLS. – ajb

1

sembra che funziona da dire

public static final <something> x; 
static { 
    x = <whatever>; 
} 

ma non

public static final <something> x; 
static { 
    MyClass.x = <whatever>; 
} 

io non so perché, ma questo è il comportamento che sto ottenendo. Per evitare questo nel tuo esempio, cambia semplicemente Test.map in map e cambia il nome dell'altra variabile map.

P.S. La risposta di Robby spiega il motivo del comportamento.

0

Ho realizzato una soluzione alternativa, utilizzando un metodo per inizializzare il campo anziché un blocco statico.All'interno del metodo, la variabile può essere denominata indipendentemente dal nome che vuole essere denominata:

public static final Map<String,Object> map = initMap(); 

private static Map<String,Object> initMap() { 
    ... 
} 
Problemi correlati