在验证《Core Java》第9版4-5代码时,发现程序输出结果和自己理解的不太一样。
import java.util.Random;
class Employee {
private static int nextId;
private int id;
private String name = "";
private double salary;
static {
Random generator = new Random();
nextId = generator.nextInt(10000);
}
{
id = nextId;
nextId++;
}
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public Employee(double salary) {
this("Employee #" + nextId, salary);
}
public Employee() {
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public int getId() {
return id;
}
}
public class ConstructorTest {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry", 40000);
staff[1] = new Employee(60000);
staff[2] = new Employee();
for (Employee e : staff) {
System.out.println("id = " + e.getId() + ", name = " + e.getName()
+ ", salary = " + e.getSalary());
}
}
}
以下是输出结果:
id = 6943, name = Harry, salary = 40000.0
id = 6944, name = Employee #6944, salary = 60000.0
id = 6945, name = , salary = 0.0
根据第一条语句得出静态初始化块生成的nextId为6943,然后在初始化块中id被赋值为6943,nextId自增后为6944。再执行第一个构造函数;
那么对于第二个对象来说,就应该直接执行初始化块,此时id为6944,nextId自增为6945。
再执行第二个构造函数,此时this("Employee #" + nextId, salary);语句中的nextId应该为6945,为什么输出结果为6944呢?
迷茫2017-04-18 10:49:39
이 클래스의 초기화 순서는 실제로 결과를 통해서만 이해할 수 있는 마법 같은 문제입니다.
테스트를 위해 중단점을 설정했습니다. staff[0] = new Employee("Harry", 40000);
과 staff[2] = new Employee();
모두 생성자 이전에 실행되는 코드 블록이지만, staff[1] = new Employee(60000);
가 먼저 실행되어 this("Employee #" + nextId, salary);
, 그 다음 코드 블록, public Employee(String name, double salary)
이 실행됩니다. 건설자. 2
을 사용하면 예상대로 코드 블록이 생성자 앞에 옵니다.
PHPz2017-04-18 10:49:39
일반적으로 Java 컴파일러는 인스턴스 초기화 블록을 생성자에 복사합니다. 특정 위치는 상위 클래스의 생성자를 호출한 후 생성자의 명령문 앞이지만 예외가 있습니다. 공식 Java Tutorial에서는 초기화 블록이 각 생성자에 복사된다고 나와 있는데 이는 실제로 엄격하지 않습니다.
특히 이 예에서는 컴파일러가 초기화 블록을 각 생성자에 복사하는 경우 생성자에서 다른 생성자가 호출되면 초기화 블록이
처럼 두 번 실행됩니다. 예 으아아아컴파일러가 초기화 블록의 코드를 public Employee(double salary)
및 public Employee(String name, double salary)
에 복사하면 이 초기화 블록이 두 번 실행됩니다. 이러한 상황을 피하기 위해 컴파일러는 public Employee(double salary)
을 발견했습니다. 이 클래스의 다른 생성자가 호출되면 초기화 블록의 코드가 이 생성자에 복사되지 않습니다.
즉, 두 번째 객체를 초기화할 때 이 초기화 블록은 this("Employee #" + nextId, salary);
호출 이후까지 연기되었다가 Employee(String name, double salary)
이 실행될 때 실행되는 것으로 결정됩니다. to pass 매개변수 nextId가 사용될 때, 이는 여전히 증가되지 않은 값입니다.
이 시공방법을
출력 결과는
이 됩니다. 으아아아이전 상황을 수정한 후 클래스 파일을 디컴파일하면 컴파일러의 최종 출력을 볼 수 있습니다. 여기에는 세 가지 구성 방법만 게시되어 있으며 두 번째 구성 방법은 복사 및 초기화되지 않았음을 명확하게 알 수 있습니다. 블록의 내용은 다른 생성자 메서드를 직접 호출합니다.
으아아아