In Java, can a final field be initialized from a constructor helper?

我是研究僧i 提交于 2019-12-05 08:23:29

问题


I have a final non-static member:

private final HashMap<String,String> myMap;

I would like to initialize it using a method called by the constructor. Since myMap is final, my "helper" method is unable to initialize it directly. Of course I have options:

I could implement the myMap initialization code directly in the constructor.

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

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

    // other initialization stuff unrelated to myMap
}

I could have my helper method build the HashMap, return it to the constructor, and have the constructor then assign the object to 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;
}

Method #2 is fine, however, I'm wondering if there's some way I could allow the helper method to directly manipulate myMap. Perhaps a modifier that indicates it can only be called by the 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...
}

回答1:


Method #2 is your best option. The problem is that if you have an assignment in a private method there is nothing preventing other code in the class outside the constructor calling it, which would then create an issue with an attempted second assignment to the final field.

Java has no construct of a separate method that can only be called during construction.

For completeness, we can make a third option, where you assign the map at initialization and then have the helper method fill it:

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

And then:

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

And if you really want to be confusing you can use an initializer instead of a constructor, but you should not do that, so unless you really need to know, I won't expand on that.




回答2:


How about implementing a private constructor that initializes your HashMap, and then have your main constructor(s) call that private constructor?

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

You can modify the signature of the private helper constructor as needed (e.g. to provide parameter data or to make the signature distinct from any public constructors).




回答3:


Option #2 is the most resuable option, because you can share it among all constructors. What we would need here, are collection initializers of c#. :)

(BTW: #3 won't compile)



来源:https://stackoverflow.com/questions/2859577/in-java-can-a-final-field-be-initialized-from-a-constructor-helper

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!