4

当我定义一个 Java 类时:

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

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

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

4

4 回答 4

4

初始化块值是在构造函数分配它们之前分配的。

所以init member 1会先赋值,再init member 2赋值。

考虑JavaGeek 中的这个例子

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”将打印在无参数构造函数中
  • 9. new InitBlocksDemo(7); 该语句导致调用单参数构造函数。其余过程相同。唯一的区别是 name 没有重新分配一个新值,因此它将打印null
于 2013-07-24T08:13:01.047 回答
3

不同之处在于分配发生的时间。在构造函数运行之前为字段分配 const 值,因此如果将此行添加到构造函数:

System.out.println(str);

在您在构造函数中分配新值之前,您会看到旧值就在那里。

除此之外没有太大的区别,使用哪个主要是个人喜好。

我个人可以直接分配作为字段声明的一部分 - 这就是我所做的。

于 2013-07-24T08:12:54.850 回答
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;
    }
}
于 2013-07-24T08:14:17.137 回答
1

以我个人的经验,这一切都与对象初始化的昂贵或详细程度有关。其次,您也可以将其视为惰性创建与主动创建。如果只涉及构造函数,我通常会在实例变量级别创建对象。如果有进一步的调用来初始化相关成员,那么肯定会将该调用移至构造函数或需要初始化的方法。

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

于 2013-07-24T08:18:25.207 回答