Java类的实例化顺序
巴扎黑
巴扎黑 2017-04-18 10:47:39
0
2
701

在验证《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呢?

巴扎黑
巴扎黑

모든 응답(2)
迷茫

이 클래스의 초기화 순서는 실제로 결과를 통해서만 이해할 수 있는 마법 같은 문제입니다.
테스트를 위해 중단점을 설정했습니다. 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을 사용하면 예상대로 코드 블록이 생성자 앞에 옵니다.

으아악
PHPzhong

일반적으로 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가 사용될 때, 이는 여전히 증가되지 않은 값입니다.
이 시공방법을

으로 바꾸면 으아아아

출력 결과는

이 됩니다. 으아아아

이전 상황을 수정한 후 클래스 파일을 디컴파일하면 컴파일러의 최종 출력을 볼 수 있습니다. 여기에는 세 가지 구성 방법만 게시되어 있으며 두 번째 구성 방법은 복사 및 초기화되지 않았음을 명확하게 알 수 있습니다. 블록의 내용은 다른 생성자 메서드를 직접 호출합니다.

으아아아
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿