构造器初始化
先来看看下面这段代码:
public class ConstructTest {
private int n;
public ConstructTest() {
//通过构造器来初始化
n = 5;
}
}
以上代码通过无参构造器来对全局变量 n 进行初始化,n 首先会被赋值为 0,然后变成 5。对于基本类型和对象引用,编译器不会强制要使用构造器或者别的方式来对其进行初始化,因为它们在定义的时候初始化就已经得到了保证。例如:int 型的初始值为 0,Random 型的初始值为 null。
为了验证初始化顺序,我们看看下面这段:
public class ConstructTest {
public ConstructTest() {
//第二次被初始化
t = new Table(11);
}
//定义的时候被第一次初始化
Table t = new Table(1);
Table t2 = new Table(2);
public static void main(String[] args) {
ConstructTest c = new ConstructTest();
}
}
class Table{
//有参构造器
public Table(int num) {
System.out.println("the num of table: " + num);
}
}
以上代码的输出结果是:
the num of table: 1
the num of table: 2
the num of table: 11
我们可以看到 Table 的对象都会在调用构造器之前得到初始化,其中对象 t 被初始化了两次,一次是在调用构造器之前,也就是定义的时候,另一次是在调用期间(第一次引用的对象将被丢弃,并作为垃圾回收)。
静态变量初始化
static 修饰的变量即为静态变量,无论创建多少个对象,静态变量都只占用一份存储区域,而且 static 关键字不能作用于局部变量。
public class StaticTest {
public static void main(String[] args) {
new Book();
new Book();
}
}
class Paper{
//有参构造器
public Paper(int n) {
System.out.println("paper construtor: " + n);
}
public void p(){
System.out.println("p method");
}
}
class Book{
//变量 p1
Paper p1 = new Paper(1);
public Book() {
System.out.println("book construtor");
p2.p();
}
//静态变量 p2
static Paper p2 = new Paper(2);
}
输出结果是:
paper construtor: 2
paper construtor: 1
book construtor
p method
paper construtor: 1
book construtor
p method
我们可以看到初始化的顺序,首先是静态变量,然后是非静态变量,然后是构造器。当 Book 的对象创建的时候,静态变量 p2 就会被初始化,并且无论之后创建多少个 Book 的对象,p2 不会再次被初始化。
非静态实例初始化
public class Cats {
Cat cat;
{
cat = new Cat(1);
}
public Cats() {
System.out.println("cats contrutor");
}
public Cats(int num) {
cat.test(num);
}
public static void main(String[] args) {
new Cats();
new Cats(2);
}
}
class Cat {
public Cat(int num) {
System.out.println("cat constructor:" + num);
}
public void test(int num){
System.out.println("test methos: " + num);
}
}
输出结果:
cat constructor:1
cats contrutor
cat constructor:1
test methos: 2
从打印结果我们可以看到,初始化顺序是,非静态变量,非静态代码块,然后才是构造器。而且每次调用构造器(无论是哪一个构造器)时,非静态变量和非静态代码块都会初始化一次。
对象创建过程
我们现在来总结一下对象的创建过程:
- 当我们首次访问类(以 Book 为例)的对象时,或者类的静态方法/静态变量时,Java 解析器会查找类路径,以查找类文件;
- 然后载入 Book.class,有关静态初始化动作都会执行,因此,静态初始化只会在 Class 对象首次加载的时候执行一次。
- 当通过 new 关键字来创建 book 对象的时候,将在堆上为 book 对象分配足够的存储空间。
- 这块存储空间会被清零,自动将 book 对象中的所有成员变量进行初始化,如果是基本类型会被设置为默认值,如果是对象引用会被设置为 null。
- 执行所有出现于字段定义处的初始化动作。
- 执行构造器。