2014-11-06 20 views
5

Aby odróżnić pola instancji i zmiennej lokalnej o tej samej nazwie możemy zakwalifikować dostęp do pola z prefiksem this.:Przypisywanie statycznego do końcowego dziedzinie samej nazwie

class Test { 
    public final Foo x; 

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

Próbuję zrobić to samo w statycznym kontekście przez kwalifikowanie dostępu z nazwą klasy:

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); 
    } 
} 

Kompilator nie chce mieć nic wspólnego z tym kodem. Mam kilka zmiennych takich jak ta i dla wszystkich z nich ciągle krzyczy: "nie można przypisać wartości do zmiennej końcowej". Jeśli I nie przypisuje do tego wartości, zamiast tego narzeka "zmienna nie zainicjowana". Jeśli przypiszę do pola statycznego na początku i postaram się, aby mapa stała się niemożliwa do zmodyfikowania, narzeka, że ​​"zmienna mogła już zostać przypisana". Nie jest z niczego zadowolony.

Czy to błąd w języku, czy błąd w kompilatorze? Jaki jest najlepszy sposób, aby zmusić kompilator do działania zgodnie z poleceniem?

+1

Użyj dwóch różnych nazw. Nie ma powodu, aby 'mapa' wewnątrz bloku statycznego miała taką samą nazwę jak statyczne pole' map'. – ajb

+0

Zmiana nazwy działa, ale jest brzydka, ponieważ wielokrotnie używam zmiennych w bloku inicjalizatora i będą one bardziej znaczące z ich własnymi nazwami. Zastanawiałem się, czy było coś lepszego. – Boann

Odpowiedz

5

Najprostszym sposobem rozwiązania jest następująca:

import java.util.*; 

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

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

     map = Collections.unmodifiableMap(contents); 
    } 
} 

Jakoś wydaje się, że jeśli zakwalifikować stała z nazwą klasy w Javie 8, kompilator nie będzie mieć.

Aktualizacja

Po jakimś bardziej kopanie, wydaje się, że Java Language Specification wyraźnie stwierdza, że ​​prosty (bez zastrzeżeń) Nazwa musi być wykorzystane do przypisania pól końcowych (podkreślenie moje):

Dla każdego dostępu zmiennej lokalnej lub pustego pola końcowego x, x musi być definitywnie przypisane przed dostępem lub wystąpi błąd podczas kompilacji.

Podobnie, każda pusta zmienna końcowa musi zostać przypisana co najwyżej jeden raz; musi być definitywnie nieprzypisany, gdy pojawi się przypisanie do niego.

Takie przypisanie jest zdefiniowany występuje wtedy i tylko wtedy, gdy albo prosty nazwą zmiennej (lub na pole, tak prosta nazwa zakwalifikowane przez to) występuje z lewej strony zadanie operatora.

+1

Dzięki za śledzenie tego w JLS. – ajb

1

Wygląda na to, że działa powiedzieć

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

ale nie

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

nie jestem pewien dlaczego, ale to zachowanie Dostaję. Aby tego uniknąć we własnym przykładzie, po prostu zmień Test.map na map i zmień nazwę innej zmiennej map.

P.S. Odpowiedź Robby'ego wyjaśnia przyczynę tego zachowania.

0

Zrobiłem obejście, używając metody do zainicjowania pola zamiast bloku statycznego.Wewnątrz metody zmienna może oczywiście być nazwana niezależnie od nazwy foo, której chce się nazywać:

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

private static Map<String,Object> initMap() { 
    ... 
} 
Powiązane problemy