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

示例1:

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

示例2:

class A {
    B b;

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

当前回答

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

检查孙的解释和建议

在本教程中:

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

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

ExpensiveObject o;

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

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

其他回答

其实很不一样:

声明发生在构建之前。因此,如果在两个位置都初始化了变量(本例中为b),构造函数的初始化将取代在类级别所做的初始化。

所以在类级别声明变量,在构造函数中初始化它们。

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

检查孙的解释和建议

在本教程中:

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

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

ExpensiveObject o;

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

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

使用依赖注入或延迟初始化总是更可取的,已经在其他回答中详细解释过了。

当你不想或不能使用这些模式时,对于基元数据类型,有三个令人信服的原因,我可以想到为什么最好在构造函数之外初始化类属性:

避免重复=如果你有多个构造函数,或者当你需要添加更多构造函数时,你将不必在所有构造函数体中重复初始化; 改进的可读性=你可以很容易地从类外部判断哪些变量需要初始化; 减少代码行数=在声明时每执行一次初始化,构造函数中就会减少一行。

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

class A {
    int b;

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

    // primary ctor
    A(int b) {
         this.b = 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.
        }
    }

    // ...

}