찾다

 >  Q&A  >  본문

Java类的实例化顺序

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

巴扎黑巴扎黑2802일 전704

모든 응답(2)나는 대답할 것이다

  • 迷茫

    迷茫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을 사용하면 예상대로 코드 블록이 생성자 앞에 옵니다.

    으아악

    회신하다
    0
  • PHPz

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

    으로 바꾸면 으아아아

    출력 결과는

    이 됩니다. 으아아아

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

    으아아아

    회신하다
    0
  • 취소회신하다