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

示例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初始化。

其他回答

没有区别——实例变量初始化实际上是由编译器放在构造函数中。 第一个变体可读性更强。 你不能对第一个变体进行异常处理。 另外还有初始化块,它也由编译器放在构造函数中: { a =新a (); }

检查孙的解释和建议

在本教程中:

但是,字段声明不是任何方法的一部分,因此它们不能像语句那样被执行。相反,Java编译器自动生成实例字段初始化代码,并将其放入类的构造函数中。初始化代码按照在源代码中出现的顺序插入构造函数,这意味着字段初始化器可以使用在它之前声明的字段的初始值。

此外,您可能希望惰性地初始化字段。如果初始化字段是一个昂贵的操作,你可以在需要的时候立即初始化它:

ExpensiveObject o;

public ExpensiveObject getExpensiveObject() {
    if (o == null) {
        o = new ExpensiveObject();
    }
    return o;
}

最后(正如Bill所指出的),为了依赖管理,最好避免在类中的任何地方使用new操作符。相反,使用依赖注入更可取——即让其他人(另一个类/框架)实例化并注入你的类中的依赖项。

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

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不太灵活。如果您添加了另一个构造函数,则需要记住在该构造函数中实例化字段。直接实例化字段,或者在getter中引入延迟加载。

如果实例化需要的不仅仅是一个简单的new,请使用初始化块。不管使用的构造函数是什么,这个函数都将运行。如。

public class A {
    private Properties properties;

    {
        try {
            properties = new Properties();
            properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
        } catch (IOException e) {
            throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
        }
    }

    // ...

}

第二种选择更可取,因为它允许在ctors中使用不同的逻辑进行类实例化,并使用ctors链接。如。

class A {
    int b;

    // secondary ctor
    A(String b) {
         this(Integer.valueOf(b));
    }

    // primary ctor
    A(int b) {
         this.b = b;
    }
}

所以第二种选择更加灵活。