2010-05-18 14 views
38

que tienen un miembro no static final:En Java, ¿se puede inicializar un campo final desde un ayudante de constructor?

private final HashMap<String,String> myMap; 

me gustaría inicializarlo utilizando un método llamado por el constructor. Como myMap es final, mi método de "ayuda" no puede inicializarlo directamente. Por supuesto que tengo opciones:

Podría implementar el código de inicialización myMap directamente en el constructor.

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

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

    // other initialization stuff unrelated to myMap 
} 

pude tener mi método de ayuda construir el HashMap, devuélvalo al constructor, y tienen el constructor a continuación, asignar el objeto a myMap. Método

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

# 2 está muy bien, sin embargo, me pregunto si hay alguna manera de que pudiera permitir que el método de ayuda para manipular directamente myMap. ¿Tal vez un modificador que indique que solo puede ser llamado por el constructor?

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

¿Sabes lo que harán las personas que responden tu pregunta? Sí, lo probarán abriendo Eclipse y copiando y pegando su código. :) – Simon

+5

@Simon Mi pregunta está solicitando una alternativa a lo que he intentado. Me pregunto si alguien con un mejor conocimiento de ese idioma que yo pueda guiarme hacia una palabra clave o paradigma que desconozco. – csj

+3

la respuesta es No. Fuente: especificación del lenguaje Java 8.3.1.2 – mihi

Respuesta

12

Método n. ° 2 es su mejor opción. El problema es que si tienes una asignación en un método privado, no hay nada que impida que otro código en la clase esté fuera del constructor que lo llama, lo que crearía un problema con una segunda asignación intentada al campo final.

Java no tiene ningún constructo de un método separado que solo se pueda invocar durante la construcción.

Para completar, podemos hacer una tercera opción, en la que asignará el mapa en la inicialización y luego tener el método de ayuda llenarlo:

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

Y luego:

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... 
    } 

Y si realmente quiero ser confuso puedes usar un inicializador en lugar de un constructor, pero no deberías hacer eso, así que a menos que realmente necesites saberlo, no ampliaré eso.

+5

En realidad, Java tiene. Se llama constructor ;-) – Joey

+1

@Johannes no, quiere decir que no hay designación de subconstructor que permita la asignación de variables finales con la condición de que el método solo pueda ser llamado desde el constructor. – corsiKa

+0

@Yishai. Gracias por la alternativa. Además, con respecto a los inicializadores, no creo que funcione de todos modos, ya que los contenidos de HashMap dependen realmente del argumento dado al constructor. – csj

1

La opción n. ° 2 es la opción más resuable, porque puede compartirla entre todos los constructores. Lo que necesitaríamos aquí, son los inicializadores de colección de C#. :)

(Por cierto: # 3 no se compilará)

+0

Gracias por su ayuda Simon. Sabía desde el primer momento que el # 3 no compilaría. Tenía la esperanza de que hubiera una forma de legalizarlo garantizando que el ayudante solo podría ser invocado por el constructor. Parece que esto no es posible. – csj

13

¿Qué hay de la implementación de un constructor privado que inicializa el HashMap, y luego tener su constructor principal (s) que llame constructor privado?

Por ejemplo-

// 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. 
} 

Usted puede modificar la firma del constructor de ayuda privado, según sea necesario (por ejemplo, para proporcionar datos de parámetros o para hacer la firma distinta de cualquier constructores públicos).

+0

Creo que esta solución es a lo que @Joey aludía cuando dijo: "En realidad, Java tiene. Se llama constructor", en respuesta a la observación de Yishai de que "Java no tiene una construcción de un método separado que solo se pueda llamar durante construcción." – cjerdonek

+0

Me gusta mucho esta idea. Desafortunadamente, me impide dar al método un nombre razonable (como, InitializeMyMap) que representa lo que se está inicializando. Gracias por publicar en una vieja pregunta. Siempre aprecio nuevas ideas o aclaraciones de las anteriores. – csj

+0

Gracias, @csj. Estaba buscando una respuesta a la misma pregunta y pensé en esto. Ninguno de los enfoques propuestos anteriormente funcionaría muy bien para mi caso de uso al inicializar simultáneamente varios campos finales. En cuanto al nombre, sí, podría ser mejor. Pero al menos es consistente con los constructores inicializando algo. :) Soy nuevo en Java y no me sorprendería si hay una solución aún mejor por ahí. – cjerdonek

Cuestiones relacionadas