web-dev-qa-db-fra.com

En Java, un dernier champ peut-il être initialisé à partir d'un assistant de constructeur?

J'ai un membre final non statique:

private final HashMap<String,String> myMap;

Je voudrais l'initialiser en utilisant une méthode appelée par le constructeur. Étant donné que MyMap est final, ma méthode "assistant" est incapable de l'initialiser directement. Bien sûr, j'ai des options:

Je pourrais implémenter le code d'initialisation MyMap directement dans le constructeur.

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

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

    // other initialization stuff unrelated to myMap
}

Je pourrais avoir ma méthode d'assistance construire le hashmap, le renvoyer au constructeur et que le constructeur assigne puis l'objet à 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;
}

La méthode n ° 2 est bien, cependant, je me demande s'il y a une manière que je puisse permettre à la méthode de l'assistance de manipuler directement MyMap. Peut-être qu'un modificateur qui l'indique ne peut être appelé que par le constructeur?

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

La méthode n ° 2 est votre meilleure option. Le problème est que si vous avez une affectation dans une méthode privée, rien n'empêche d'autres code dans la classe en dehors du constructeur qui l'appelait, ce qui créerait ensuite un problème avec une tentative de deuxième affectation au dernier champ.

Java n'a pas de construction d'une méthode distincte qui ne peut être appelée que pendant la construction.

Pour une complétude, nous pouvons faire une troisième option, où vous attribuez la carte à l'initialisation, puis la méthode de l'assistance remplit-la:

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

Puis:

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

Et si vous voulez vraiment être déroutant, vous pouvez utiliser un initialiseur au lieu d'un constructeur, mais vous ne devriez pas le faire, alors si vous n'avez pas besoin de savoir, je ne développerai pas cela.

15
Yishai

Que diriez-vous de mettre en œuvre un constructeur privé qui initialise votre HASHMAP, puis demandez à votre constructeur principal que le constructeur privé?

Par exemple--

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

Vous pouvez modifier la signature du constructeur d'assistance privé selon vos besoins (par exemple, pour fournir des données de paramètre ou pour rendre la signature distincte de tous les constructeurs publics).

13
cjerdonek

L'option n ° 2 est l'option la plus réutilisable, car vous pouvez le partager entre tous les constructeurs. Ce dont nous aurons besoin ici, sont des initialisateurs de collecte de C #. :)

(BTW: # 3 ne compilera pas)

1
Simon