这两种方法都有什么优势吗?

示例1:

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

示例2:

class A {
    B b;

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

当前回答

我今天以一种有趣的方式被烧伤了:

class MyClass extends FooClass {
    String a = null;

    public MyClass() {
        super();     // Superclass calls init();
    }

    @Override
    protected void init() {
        super.init();
        if (something)
            a = getStringYadaYada();
    }
}

看到错误了吗?结果是,在父类构造函数被调用之后才调用a = null初始化式。由于超类构造函数调用init(), a的初始化之后是a = null初始化。

其他回答

这两种方法都可以接受。注意,在后一种情况下,如果存在另一个构造函数,b=new b()可能无法初始化。将构造函数外部的初始化器代码看作一个公共构造函数,代码将被执行。

我认为例2更可取。我认为最佳实践是在构造函数外部声明,并在构造函数中初始化。

第二个例子是惰性初始化。第一个是更简单的初始化,它们本质上是一样的。

    class MyClass extends FooClass {
    String a = null;

    public MyClass() {
        super();     // Superclass calls init();
    }

    @Override
    protected void init() {
        super.init();
        if (something)
            a = getStringYadaYada();
    }
}

关于以上,

String a = null;

Null init可以避免,因为它是默认值。 然而,如果您需要另一个默认值, 然后,由于初始化顺序不受控制, 我将修改如下:

class MyClass extends FooClass 
{
    String a;
    {
        if( a==null ) a="my custom default value";
    }
    ...

另一种选择是使用依赖注入。

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.