当我基于我的c++知识使用Java时,我喜欢使用以下方式初始化变量。

public class ME {
    private int i;

    public ME() {
         this.i = 100;
    }
}

一段时间后,我改变了习惯

public class ME {
    private int i = 100;

    public ME() {
    }
}

我遇到了其他人的源代码,一些使用第1公约,其他人使用第2公约。

请问你们都推荐哪个会议?为什么?


当前回答

我认为第一个方法的唯一问题是,如果您计划添加更多的构造函数。这样你就会重复代码,可维护性也会受到影响。

其他回答

我会说,这取决于默认值。例如

public Bar
{
  ArrayList<Foo> foos;
}

我将在构造函数之外创建一个新的数组列表,如果我总是假设foo不能为空的话。如果Bar是一个有效的对象,不关心foos是否为空,我将把它放在构造函数中。

您可能不同意,并说将对象置于有效状态是构造函数的工作。然而,如果显然所有的构造函数都应该做完全相同的事情(初始化foo),为什么要重复该代码呢?

我倾向于使用第二个,以避免复杂的构造函数(或无用的构造函数),我也不认为这是一个初始化(即使它是一个初始化),而更像是给出一个默认值。

例如,在第二个代码片段中,可以删除构造函数,从而获得更清晰的代码。

我几乎总是在构造函数中进行初始化,这有两个原因,一是我认为它增加了可读性(更干净),二是构造函数中比一行中有更多的逻辑控制。即使最初实例变量不需要逻辑,在构造函数中使用它可以在将来需要时更灵活地添加逻辑。

对于上面提到的关于多个构造函数的问题,这很容易解决,只需使用一个无参数构造函数初始化所有实例变量,然后每个构造函数在第一行调用this()。这解决了冗余问题。

我认为第一个方法的唯一问题是,如果您计划添加更多的构造函数。这样你就会重复代码,可维护性也会受到影响。

这取决于你初始化的是什么,例如,如果涉及到检查异常,你不能只使用字段初始化。例如:

public class Foo {
    FileInputStream fis = new FileInputStream("/tmp"); // throws FileNotFoundException
}

将导致编译时错误,除非你还包含一个声明该检查异常的构造函数,或者扩展一个声明该检查异常的超类,例如:

public Foo() throws FileNotFoundException {}