new
,然后一切就绪了:)这里我们将讨论当我们写的时候计算机和 Java 机器内部发生了什么,例如:
Cat cat = new Cat();
我们之前已经讨论过这个问题,但为了以防万一,我们会提醒您:
- 首先,分配存储对象的内存。
- 接下来,Java 机器创建对象的引用(在我们的例子中,引用是 Cat cat)。
- 最后,初始化变量并调用构造函数(我们将更详细地研究这个过程)。
public class Vehicle {
public static int vehicleCounter = 0;
private String description = "Vehicle";
public Vehicle() {
}
public String getDescription() {
return description;
}
}
public class Truck extends Vehicle {
private static int truckCounter = 0;
private int yearOfManufacture;
private String model;
private int maxSpeed;
public Truck(int yearOfManufacture, String model, int maxSpeed) {
this.yearOfManufacture = yearOfManufacture;
this.model = model;
this.maxSpeed = maxSpeed;
Vehicle.vehicleCounter++;
truckCounter++;
}
}
该类Truck
是卡车的一个实现,其中包含代表其年份、型号和最大速度的字段。现在我们要创建一个这样的对象:
public class Main {
public static void main(String[] args) throws IOException {
Truck truck = new Truck(2017, "Scania S 500 4x2", 220);
}
}
对于 Java 机器,该过程将如下所示:
-
发生的第一件事是类的静态变量
Vehicle
被初始化。是的,我说的是Vehicle
类,不是Truck
。静态变量在调用构造函数之前初始化,这从父类开始。让我们尝试验证这一点。我们将类vehicleCounter
中的字段设置Vehicle
为 10 并尝试在Vehicle
和Truck
构造函数中显示它。public class Vehicle { public static int vehicleCounter = 10; private String description = "Vehicle"; public Vehicle() { System.out.println(vehicleCounter); } public String getDescription() { return description; } } public class Truck extends Vehicle { private static int truckCount = 0; private int yearOfManufacture; private String model; private int maxSpeed; public Truck(int yearOfManufacture, String model, int maxSpeed) { System.out.println(vehicleCounter); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Vehicle.vehicleCounter++; truckCount++; } }
我们特意将 println 语句放在构造函数的最开头,以确保在显示
Truck
时卡车的字段尚未初始化。vehicleCounter
结果如下:
10 10
-
父类的静态变量初始化完成后,再对子类的静态变量进行初始化。在我们的例子中,这是班级
truckCounter
的领域Truck
。让我们做另一个实验,我们将尝试在初始化其他字段之前显示构造函数
truckCounter
内部的值:Truck
public class Truck extends Vehicle { private static int truckCounter = 10; private int yearOfManufacture; private String model; private int maxSpeed; public Truck(int yearOfManufacture, String model, int maxSpeed) { System.out.println(truckCounter); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Vehicle.vehicleCounter++; truckCounter++; } }
如您所见,在构造函数开始时,值 10已经分配给我们的静态变量
Truck
。 -
现在还不是构造函数的时间!变量初始化继续。 第三次初始化父类的非静态变量。 如您所见,继承使创建对象的过程变得非常复杂,但是您对此无能为力:您只需要记住编程中的一些东西:)
作为实验,我们可以
description
在Vehicle
类中为变量赋一些初始值,然后在构造函数中更改它。public class Vehicle { public static int vehicleCounter = 10; private String description = "Initial value of the description field"; public Vehicle() { System.out.println(description); description = "Vehicle"; System.out.println(description); } public String getDescription() { return description; } }
让我们运行
main()
创建卡车的方法:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }
我们得到以下结果:
Initial value of the description field Vehicle
这证明在
Vehicle
构造函数开始时该description
字段已经被赋值。 -
最后,是构造函数的时间了! 更准确地说,是基类构造函数的时候了。它在对象创建过程的第四步被调用。
这也很容易验证。让我们尝试向控制台输出两行:一行在
Vehicle
基类构造函数中,第二行在Truck
构造函数中。我们需要确信Vehicle
首先显示里面的行:public Vehicle() { System.out.println("Hello from the Vehicle constructor!"); } public Truck(int yearOfManufacture, String model, int maxSpeed) { System.out.println("Hello from the Truck constructor!"); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Vehicle.vehicleCounter++; truckCounter++; }
我们将运行我们的
main()
方法并查看结果:Hello from the Vehicle constructor! Hello from the Truck constructor!
出色的。这意味着我们没有弄错 :) 让我们继续。
-
现在是初始化子类(即我们的类)的非静态字段的
Truck
时候了。被实例化的类中的字段直到第五步才被初始化!令人惊讶,但确实如此 :) 同样,我们将做一个简单的检查——就像父类一样:我们将一些初始值赋给变量,maxSpeed
并在Truck
构造函数中检查该值是否在构造函数启动之前分配:public class Truck extends Vehicle { private static int truckCounter = 10; private int yearOfManufacture; private String model; private int maxSpeed = 150; public Truck(int yearOfManufacture, String model, int maxSpeed) { System.out.println("Initial value of maxSpeed = " + this.maxSpeed); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Vehicle.vehicleCounter++; truckCounter++; } }
控制台输出:
Initial value of maxSpeed = 150
可以看到, 构造函数启动时
Truck
,maxSpeed
已经等于150了! -
Truck
调用子类的构造函数。只有在这一点上,最后,我们正在实例化的类的构造函数才会被调用!
只有在第六步中,这些字段才会被赋予我们作为参数传递给卡车的值。
如您所见,“构建”一辆卡车,即对象创建过程,并不简单。但我们似乎已将其分解为最小的部分 :)
GO TO FULL VERSION