Should I instantiate instance variables on declaration or in the constructor?

前端 未结 15 1842

Is there any advantage for either approach?

Example 1:

class A {
    B b = new B();
}

Example 2:

class A {
    B b;         


        
相关标签:
15条回答
  • 2020-11-22 07:02

    The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.

    0 讨论(0)
  • 2020-11-22 07:02

    The second option is preferable as allows to use different logic in ctors for class instantiation and use ctors chaining. E.g.

    class A {
        int b;
    
        // secondary ctor
        A(String b) {
             this(Integer.valueOf(b));
        }
    
        // primary ctor
        A(int b) {
             this.b = b;
        }
    }
    

    So the second options is more flexible.

    0 讨论(0)
  • 2020-11-22 07:02

    It's quite different actually:

    The declaration happens before construction. So say if one has initialized the variable (b in this case) at both the places, the constructor's initialization will replace the one done at the class level.

    So declare variables at the class level, initialize them in the constructor.

    0 讨论(0)
  • 2020-11-22 07:02
        class MyClass extends FooClass {
        String a = null;
    
        public MyClass() {
            super();     // Superclass calls init();
        }
    
        @Override
        protected void init() {
            super.init();
            if (something)
                a = getStringYadaYada();
        }
    }
    

    Regarding the above,

    String a = null;
    

    null init could be avoided since anyway it's the default. However, if you were to need another default value, then, because of the uncontrolled initialization order, I would fix as follow:

    class MyClass extends FooClass 
    {
        String a;
        {
            if( a==null ) a="my custom default value";
        }
        ...
    
    0 讨论(0)
  • 2020-11-22 07:03

    There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.

    0 讨论(0)
  • 2020-11-22 07:09

    Another option would be to use Dependency Injection.

    class A{
       B b;
    
       A(B b) {
          this.b = b;
       }
    }
    

    This removes the responsibility of creating the B object from the constructor of A. This will make your code more testable and easier to maintain in the long run. The idea is to reduce the coupling between the two classes A and B. A benefit that this gives you is that you can now pass any object that extends B (or implements B if it is an interface) to A's constructor and it will work. One disadvantage is that you give up encapsulation of the B object, so it is exposed to the caller of the A constructor. You'll have to consider if the benefits are worth this trade-off, but in many cases they are.

    0 讨论(0)
提交回复
热议问题