2010-05-18 17 views
38

Mam ostateczny non-statycznego użytkownik:W języku Java, czy pole końcowe może zostać zainicjalizowane przez pomocnika konstruktora?

private final HashMap<String,String> myMap; 

chciałbym zainicjować za pomocą metody zwanej przez konstruktora. Ponieważ myMap jest ostateczna, moja metoda "pomocnika" nie jest w stanie zainicjować jej bezpośrednio. Oczywiście mam opcje:

Mogę zaimplementować kod inicjujący myMap bezpośrednio w konstruktorze.

MyConstructor (String someThingNecessary) 
{ 
    myMap = new HashMap<String,String>(); 

    myMap.put("blah","blahblah"); 
    // etc... 

    // other initialization stuff unrelated to myMap 
} 

mogę mieć moja metoda pomocnika zbudować HashMap, powrót do konstruktora i mieć konstruktor następnie przypisać obiekt do MyMap.

MyConstructor (String someThingNecessary) 
{ 
    myMap = InitializeMyMap(someThingNecessary); 

    // other initialization stuff unrelated to myMap 
} 

private HashMap<String,String> InitializeMyMap(String someThingNecessary) 
{ 
    HashMap<String,String> initializedMap = new HashMap<String,String>(); 

    initializedMap.put("blah","blahblah"); 
    // etc... 

    return initializedMap; 
} 

Sposób nr 2 jest w porządku, jednak zastanawiam się, czy istnieje jakiś sposób mogę pozwolić metoda pomocnika bezpośrednio manipulować MyMap. Być może modyfikator, który to wskazuje, może być wywołany tylko przez konstruktora?

MyConstructor (String someThingNecessary) 
{ 
    InitializeMyMap(someThingNecessary); 

    // other initialization stuff unrelated to myMap 
} 


// helper doesn't work since it can't modify a final member 
private void InitializeMyMap(String someThingNecessary) 
{ 
    myMap = new HashMap<String,String>(); 

    myMap.put("blah","blahblah"); 
    // etc... 
} 
+0

Czy wiesz, co zrobią osoby odpowiadające na twoje pytanie? Tak, wypróbują to, otwierając Eclipse i wklejając swój kod! :) – Simon

+5

@Simon Moje pytanie dotyczy alternatywy dla tego, co próbowałem. Zastanawiam się, czy ktoś o lepszej znajomości tego języka niż mnie może doprowadzić do słowa kluczowego lub paradygmatu, nie jestem świadomy. – csj

+3

odpowiedź brzmi Nie. Źródło: Specyfikacja języka Java 8.3.1.2 – mihi

Odpowiedz

12

Metoda nr 2 to najlepsza opcja. Problem polega na tym, że jeśli masz zadanie w prywatnej metodzie, nic nie stoi na przeszkodzie, aby inny kod w klasie poza konstruktorem wywoływał go, co spowodowałoby problem z próbą drugiego przypisania do końcowego pola.

Java nie ma konstrukcji oddzielnej metody, którą można wywołać tylko podczas budowy.

Dla kompletności, możemy dokonać trzecią opcję, gdzie można przypisać mapę przy inicjalizacji i wtedy metoda pomocnika wypełnić go:

private final HashMap<String, String> myMap = new HashMap<String, String(); 

, a następnie:

MyConstructor (String someThingNecessary) 
{ 
    initializeMyMap(someThingNecessary); 

    // other initialization stuff unrelated to myMap 
} 


// helper doesn't work since it can't modify a final member 
private void initializeMyMap(String someThingNecessary) 
{ 

    myMap.clear(); 
    myMap.put("blah","blahblah"); 
    // etc... 
    } 

a jeśli Naprawdę chcesz się pomylić, możesz użyć inicjalizatora zamiast konstruktora, ale nie powinieneś tego robić, więc jeśli naprawdę nie musisz tego wiedzieć, nie będę tego rozszerzał.

+5

Właściwie to Java ma. Nazywa się to konstruktorem ;-) – Joey

+1

@Johannes nie, oznacza, że ​​nie ma oznaczenia pod konstruktorem, które umożliwiłoby przypisanie zmiennych końcowych pod warunkiem, że metoda mogła zostać wywołana tylko z konstruktora. – corsiKa

+0

@ Yishai. Dzięki za alternatywę. Ponadto, w odniesieniu do inicjalizatorów, nie sądzę, by i tak działało, ponieważ zawartość HashMap jest w rzeczywistości zależna od argumentu podanego konstruktorowi. – csj

1

Opcja nr 2 jest najbardziej przydatną opcją, ponieważ można ją udostępnić pośród wszystkich konstruktorów. To, czego potrzebowalibyśmy tutaj, to inicjatory kolekcji C#. :)

(BTW: # 3 nie będzie kompilować)

+0

Dzięki za pomoc Simon. Wiedziałem od początku, że # 3 nie skompiluje się. Miałem nadzieję, że istnieje sposób, aby uczynić to legalnym, gwarantując, że pomocnik będzie dostępny tylko od konstruktora. Wygląda na to, że nie jest to możliwe. – csj

13

Jak o wdrażaniu prywatny konstruktor, który inicjuje swoją HashMap, a następnie mieć swój główny konstruktor (y) nazywamy to prywatny konstruktora?

Dla example--

// Helper function to initialize final HashMap. 
private MyConstructor() 
{ 
    myMap = new HashMap<String,String>(); 
    myMap.put("blah","blah"); 
} 

MyConstructor (String someThingNecessary) 
{ 
    // Initialize the HashMap. 
    this(); 
    // Other initialization code can follow. 
} 

Można zmodyfikować podpis prywatnego konstruktora pomocnika w razie potrzeby (na przykład w celu dostarczenia danych parametrów lub dokonania podpis różni się od jakichkolwiek konstruktorów publicznych).

+0

Myślę, że to rozwiązanie jest tym, o czym wspomniał @Joey, kiedy powiedział: "Właściwie, Java nazywa się konstruktorem", w odpowiedzi na uwagę Yishai, że "Java nie ma żadnej konstrukcji oddzielnej metody, która może być wywołana tylko podczas budowa." – cjerdonek

+0

Podobał mi się ten pomysł. Niestety, uniemożliwia mi nadanie metodzie rozsądnej nazwy (np. InitializeMyMap), która reprezentuje to, co inicjuje. Dziękuję za zamieszczenie starego pytania. Zawsze doceniam nowe pomysły lub wyjaśnienia dawnych. – csj

+0

Dzięki, @csj. Szukałem odpowiedzi na to samo pytanie i pomyślałem o tym. Żadne z proponowanych wcześniej podejść nie zadziałałoby dobrze w moim przypadku użycia jednoczesnego inicjowania kilku ostatnich pól. Jeśli chodzi o nazwę, tak, może być lepiej. Ale przynajmniej jest to zgodne z konstruktorami inicjującymi coś. :) Jestem nowy w Javie i nie byłbym zaskoczony, gdyby istniało jeszcze lepsze rozwiązanie. – cjerdonek