我应该在构造函数内部还是构造函数外部初始化变量

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

public class ME {
private int i;


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

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

public class ME {
private int i = 100;


public ME() {
}
}

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

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

184114 次浏览

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

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

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

我建议在构造函数中初始化变量。这就是它们存在的原因:确保你的对象被正确构造(初始化)。

两种方法都可以,只是风格的问题,但我更喜欢用构造函数来初始化成员。

我认为两者都是正确的编程方式,

但是我认为你的第一个选择在面向对象的方式中更正确,因为在构造函数中是对象创建的时候,也是变量应该初始化的时候。

我认为这是“照章办事”的惯例,但它是可以讨论的。

Wikipedia .

如果你在顶部或构造函数中初始化,没有太大区别,但在某些情况下,在构造函数中初始化是有意义的。

class String
{
char[] arr/*=char [20]*/; //Here initializing char[] over here will not make sense.
String()
{
this.arr=new char[0];
}
String(char[] arr)
{
this.arr=arr;
}
}

根据不同的情况有时你需要在顶部初始化有时在构造函数中初始化。

供参考,不使用构造函数初始化的其他选项:

class Foo
{
int i;
static int k;


//instance initializer block
{
//run's every time a new object is created
i=20;
}


//static initializer block
static{
//run's only one time when the class is loaded
k=18;
}
}

根据您的情况,这两种选择都是正确的。

一个非常简单的例子是:如果你有多个构造函数,它们都以相同的方式初始化变量(每个构造函数都是int x=2)。在声明时初始化变量以避免冗余是有意义的。

在这种情况下考虑最终变量也是有意义的。如果在声明时知道final变量的值,那么在构造函数外部初始化它是有意义的。但是,如果您希望类的用户通过构造函数初始化最终变量,请将初始化延迟到构造函数。

首先,不管你如何初始化字段,如果可能的话,使用final限定符将确保在多线程环境中字段值的可见性。

我发现第二种风格(一次性声明+初始化)更好。原因:

  • 它使变量的初始化一目了然。通常,在阅读一个程序并遇到一个变量时,您将首先查看它的声明(在ide中通常是自动的)。使用样式2,您可以立即看到默认值。对于样式1,还需要查看构造函数。
  • 如果有多个构造函数,就不必重复初始化(而且不能忘记初始化)。

当然,如果初始化值在不同的构造函数中是不同的(甚至在构造函数中计算),则必须在构造函数中进行。

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

public Bar
{
ArrayList<Foo> foos;
}

如果我总是假设foos不能为空,我将在构造函数外部创建new ArrayList。如果Bar是一个有效对象,不管foos是否为空,我将把它放在构造函数中。

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

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

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

它可以依赖于你正在初始化的什么,例如,如果涉及到checked异常,你不能只使用字段初始化。例如:

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

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

public Foo() throws FileNotFoundException {}