如何初始化实例成员?

时间:2013-07-24 08:09:59

标签: java

当我定义Java类时:

class A {
   private String str = "init method 1";

   public A() {
       str = "init method 2";
   }
}

我可以在定义它时初始化str或在构造函数中初始化它。我的问题是这两种方法的区别是什么?首选哪种方法?

4 个答案:

答案 0 :(得分:4)

初始化块值在构造函数赋值之前分配。

因此,将首先分配值init member 1,然后分配init member 2

theJavaGeek

考虑这个例子
class InitBlocksDemo {

    private String name ;

    InitBlocksDemo(int x) {
        System.out.println("In 1 argument constructor, name = " + this.name);
    }

    InitBlocksDemo() {
        name = "prasad";
        System.out.println("In no argument constructor, name = " + this.name);

    }

    /* First static initialization block */
    static {
        System.out.println("In first static init block ");
    }

    /* First instance initialization block  */
    {
        System.out.println("In first instance init block, name = " + this.name);
    }

    /* Second instance initialization block */
    {
        System.out.println("In second instance init block, name = " + this.name);
    }

    /* Second static initialization block  */
    static {
        System.out.println("In second static int block ");
    }

    public static void main(String args[]) {
        new InitBlocksDemo();
        new InitBlocksDemo();
        new InitBlocksDemo(7);
    }

}

此输出,

In first static init block
In second static int block
In first instance init block, name = null
In second instance init block, name = null
In no argument constructor, name = prasad
In first instance init block, name = null
In second instance init block, name = null
In no argument constructor, name = prasad
In first instance init block, name = null
In second instance init block, name = null
In 1 argument constructor, name = null

程序流程如下。

  • 当程序开始执行时,类InitBlocksDemo被加载到JVM中。
  • 静态初始化块按类在程序中出现的顺序加载时运行。
  • 现在,当静态块的执行完成时,遇到main方法。
  • 语句new InitBlocksDemo();导致无参数构造函数被调用。
  • 由于存在对super无参数构造函数的默认调用,因此控制转到超类,即Object
  • 完成后,控制权返回到我们的类并开始为实例变量提供默认值。在这种情况下,变量名称将被赋值为null
  • 现在,实例块将按照它们在程序中出现的顺序执行。我们还没有为name变量重新赋值,因此它将打印null
  • 执行实例块后,控制权转到构造函数。这里名字=“prasad”;将重新分配一个新值,因此“prasad”将在无参数构造函数中打印
  • 9.语句new InitBlocksDemo(7);导致调用单参数构造函数。其余的过程是一样的。唯一的区别是名称未重新分配新值,因此它将打印null

答案 1 :(得分:3)

区别在于分配何时发生。 在构造函数运行之前为字段分配const值,因此如果将此行添加到构造函数中:

System.out.println(str);

在构造函数中指定较新的值之前,您将看到旧的值。

除了那之外没有太大的区别,使用的主要是个人偏好。

我个人可以直接指派作为现场声明的一部分 - 这就是我所做的。

答案 2 :(得分:3)

它们之间没有区别,编译器将初始化块复制到构造函数

如果您,反编译生成的类文件

class A {
    private String str1 = "init method 1";

    private String str2;

    public A() {
        str2 = "init method 2";
    }

    public A(String str2) {
        str2 = str2;
    }
}

你可以找到

class A
{

    private String str1;
    private String str2;

    public A()
    {
        str1 = "init method 1";
        str2 = "init method 2";
    }

    public A(String str2)
    {
        str1 = "init method 1";
        str2 = str2;
    }
}

答案 3 :(得分:1)

根据我的个人经验,它完全取决于对象初始化的成本或详细程度。其次,您还可以将其视为懒惰创建与主动创建。如果只涉及构造函数,我通常会在实例变量级别创建对象。如果还有进一步的调用来初始化有问题的成员,那么肯定会将调用移动到构造函数或需要初始化的方法。

这就是为什么使用工厂方法模式,将实际的对象创建委托给另一个类。