class 字段 Java 中的初始化顺序

class fields Initialization sequence in Java

下面两段代码有什么区别:

class B{
  B(){}
}

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

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

这两种方式初始化有什么区别?另外,如果两个语句都在一个 class 中,它们的执行顺序是什么?为什么?

编辑:添加更多说明:

class C{
//1)  
  int i = 5;

 //initializers block
  {
    i =7;
  }

}

这两个语句的执行顺序是什么? i 的最终值是多少?

更新更清晰的新问题:

It sees now that I should have added more text to my question. I wanted to know what would be the sequence of execution in case both these statements(1 and 2) are in one single class for the same variable ?

您对以下内容感兴趣:

   private class Test {
        public String field = new String("1");
        {
            field = new String("2");
        }

    }

一开始field的值为1,之后会调用constructor,执行编译时放在ctor中的init block,所以field的值为"2"。

看这个例子:

http://ideone.com/72uxES

另请参阅此问答:

Default constructor vs. inline field initialization


旧版本

我想你的意思是这样的:

Object obj = new Object() 

或者

Object obj;
{
  obj = new Object();
}

花括号定义了一个范围,其中给出了变量生命周期。

假设我们有以下示例:

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    private static void checkObject(Object obj) {
        if (obj == null)
            System.out.println("Object is null");
        else
            System.out.println("Object is not null");
    }
    public static void main (String[] args) throws java.lang.Exception
    {
        Object obj;
        {
            obj = new Object();
            checkObject(obj);
        }
        checkObject(obj);
    }
}

输出是:

Object is not null
Object is not null

但是如果我们把它改成:

{
  Object obj = new Object();
  checkObject(obj);
}
checkObject(obj);

它甚至不会编译并给出这些错误信息:

Main.java:22: error: cannot find symbol
        checkObject(obj);
                    ^
  symbol:   variable obj
  location: class Ideone
1 error

首先声明一个变量obj,并在作用域内初始化 因为它是在外部声明的,所以可以在作用域之后使用。

如果仅在范围内声明和初始化,则只能在范围内使用。 生命周期与范围绑定。

如果使用大括号初始化class字段 您可以使用多个语句来初始化它们 但您也可以简单地创建一个 final 方法并调用该方法来初始化该字段。

大括号和字段初始化示例:

class A {
 private String field;
 {
   StringBuilder builder = new StringBuilder("Text").append(value)
                                                    .append(" ")
                                                    .append(otherValue);
   //make some computations 
   //append to builder
   //add to field
   field = builder.toString();
 }

提示:

The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.

查看工作示例:

http://ideone.com/X42rQI

我认为它与以下内容有关:

Initializing Instance Members

Normally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods.

Initializer blocks for instance variables look just like static initializer blocks, but without the static keyword:

{
    // whatever code is needed for initialization goes here
}

The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.

https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

基本上这意味着所有构造函数都将初始化括号之间的所有实例变量。即使您的 类 没有多个构造函数

添加了具有多个构造函数的示例

class A{
  B b;
  int index;
  String result;
  {
    b = new B();
    index = 0;
  }

  public A(int temp){
    // nothing
  }

  public A(int temp, String test){
    this.result = test;
  }

  public int getIndex(){
    return index;
  }
}

在这里使用哪个构造函数并不重要,因为括号之间的初始化被复制到两个构造函数中。 a.getIndex() 将始终 return '0'

如您所知,当我们实例化一个 class 时会调用构造函数。此外,所有 classes 都具有顶级 Class,如 JAVA 中的 Object。现在,每当我们为您的案例 A 调用任何 class 的构造函数作为 new A() 时,它都会导致我们首先调用 super() 导致 Object's 构造函数。

现在,在您的示例 1 中,您的变量 b 已在 class 本身中声明和初始化。因此,在 class A 的构造函数执行之前,变量 b 被初始化,即您在 public A() 中编写的所有代码将在 b 之后执行初始化。

在您的示例 2 中,您的变量 b 在 class 中声明,但在 A 的构造函数中初始化。如果您在 b = new B(); 行之前有一些代码,那么该代码将首先执行,然后 b 将被初始化。

参见下面的示例:

Class A{
   B b = new B();

   public A(){
      b == null; //FALSE as it has been already initialised.
   }
}

但是

Class A{
   B b ;

   public A(){
      b == null; //TRUE as it has not been initialised.
      b = new B();
      b == null; //FALSE as it has been just initialised.
   }
}