学习Java,对类的加载和初始化的全过程有一定的了解,对所发生的一切有全局性的把握,是有益的。
首先明确一点,要使用一个类,这个类必须被加载。要创建并使用这个类的对象,就必须初始化对象。
1、无继承关系的类是如何初始化的
以 Mamml 类为例子,其包含 static域和 非static域以及构造器。如下,创建一个Mammal的实例。
public class Mammal {
public static String age = PrintInit.printInit("Mammal static initialization");
public String weight = PrintInit.printInit("Mammal initialization");
Mammal(){
System.out.println("This is Mammal");
}
public static void main(String[] args) {
System.out.println("创建一个对象");
Mammal mammal = new Mammal();
}
}
结果 :
Mammal static initialization
创建一个对象
Mammal initialization
This is Mammal
注:通过一个自建的工具类来检验初始化的顺序,该类的作用是当某变量被调用时,打印相关信息。
public class PrintInit {
public static String printInit(String s){
System.out.println(s);
return s;
}
}
以上结果可以看出,创建一个类的实例,会先加载类文件,初始化 static域,然后初始化非static域,最后通过构造器创建一个对象。而且从结果可以看出,初始化 static域并不需要创建对象。
注意:所有变量会在所有方法(包括构造器)调用前得到初始化,与顺序无关。例如调换变量定义的顺序,如下,程序运行的结果相同。
public class Mammal {
Mammal(){
System.out.println("This is Mammal");
}
public String weight = PrintInit.printInit("Mammal initialization");
public static String age = PrintInit.printInit("Mammal static initialization");
public static void main(String[] args) {
System.out.println("创建一个对象");
Mammal mammal = new Mammal();
}
}
2、有继承关系的类是怎么初始化的?
假设有三个类,为多继承关系:Mammal -- Human -- Person
public class Mammal {
Mammal(){
System.out.println("This is Mammal");
}
}
public class Human extends Mammal {
Human(){
System.out.println("This is Human");
}
}
public class Person extends Human {
Person(){
System.out.println("This is Person");
}
}
在main函数中新建一个Person类的对象
public class Main {
public static void main(String[] args) {
Person person=new Person();
}
}
结果如下:
This is Mammal
This is Human
This is Person
以上可以看出,子类新建一个对象时,实际也创建了一个位于内部的父类对象。因为子类的构造函数要做的第一件事就是调用父类的构造函数。
接下来验证复杂一点的情况,假设上述三个类各自拥有static域和 非static域以及构造器,如下:
public class Mammal {
public static String age=PrintInit.printInit("Mammal static initialization");
public String weight=PrintInit.printInit("Mammal initialization");
Mammal(){
System.out.println("This is Mammal");
}
}
public class Human extends Mammal {
public static String gender=PrintInit.printInit("Human static initialization");
public String profession=PrintInit.printInit("Human initialization");
Human(){
System.out.println("This is Human");
}
}
public class Person extends Human {
public static String name=PrintInit.printInit("Person static initialization");
public String hobby=PrintInit.printInit("Person initialization");
Person(){
System.out.println("This is Person");
}
public static void main(String[] args) {
System.out.println("---static初始化完成后,创建一个对象---");
Person person=new Person();
}
}
运行Main函数,打印结果,如下:
Mammal static initialization
Human static initialization
Person static initialization
---static初始化完成后,创建一个对象---
Mammal initialization
This is Mammal
Human initialization
This is Human
Person initialization
This is Person
从结果可以看出,一个类的初始化,会先从main函数开始,先检查是否有基类,有基类则检查该基类是否还有自身的基类,直到根基类,然后加载根基类的static修饰的方法或参数,返回上一个导出类直到最初的类。至此,static的初始化完成。(简单说,要加载一个类的static域,就要先加载其基类的static域)
接下来如果新建了对象,则会初始化根基类的基本类型的变量和调用根基类的构造函数,然后返回到导出类,初始化该导出类的基本类型的变量和调用该导出类的构造函数,以此类推。(简单说,要创建一个类的对象就要先创建其基类的对象)
注:此案例中,Mammal 为根基类,Male 为Mammal 的导出类(也可以说是子类)和Person的基类(也可以说是父类或超类)