虽然每天都用Java,现在尝试做一些项目也是用的Java,但是总感觉对这门语言学习的不够深入,对Java的认识也只是停留在别人博客中所说的,没有自己独特的理解。所以最近又把《Java核心技术》又重新的读了一遍。感觉对Java的认识还是比较欠缺。感觉学会一门语言并不是说会用就可以了,真正的理解这门语言,编程能力才会有质的提升。
下面我们就先从Java中最基本的类开始,探讨一下我们写的程序中的类是何时被初始化,又是何时被加载的。
类的加载
首先我们要清楚类的初始化和类的加载是两个不同的概念。类的加载是由类的加载器完成的,比如ClassLoader就是一个用Java写的一个加载器。所谓的加载就是当程序员在命令行中执行java HelloWord
命令时,JVM会将HelloWord.java加载到内存中,然后编译成HelloWord.class文件的过程。
类的初始化
类的初始化是发生在类加载完成后,这时类会先把静态属性初始化(Java中的初始化顺序是(静态变量、静态初始化块)>(变量、初始化块)>构造器)。类一般会在一下情况下发生初始化:
- 通过new关键字创建实例
- 该类的静态方法被调用
- 使用类的非常量静态字段(static修饰的变量,语句块。被final修饰的静态字段为变异字段,不会触发类的初始化)
- 通过Class.forName()反射创建实例
- 初始化该类的某个子类
- 当包含main()方法的类启动时
类的初始化步骤
类的初始化步骤一般分为3步:
- 如果一个类存在父类的话,并且其父类还没有被初始化,则优先初始化其父类
- 如果该类存在一个初始化方法,则执行该方法
- 静态域的初始化在非静态域之前(静态域的初始化在类的额静态初始化期间,非静态域的初始化在该类的实例穿件期间)
代码
好的,下面我们通过一段简单的代码来体会一下Java中类的初始化过程。
定义父类:
package org.joea.classinit;
public class SuperClass {
int a;
static int b;
static int c = 1;
static {
b = 2;
c = 3;
System.out.println("SuperClass:static block has been initialized!");
}
public void print() {
System.out.println("SuperClass:a=" + a + ";b=" + b + ";c=" + c);
}
}
定义子类:
package org.joea.classinit;
public class SubClass extends SuperClass{
int x;
static int y=4;
static {
y=5;
System.out.println("SubClass:static block has been initialized! ");
}
public void print(){
super.print();
System.out.println("SubClass:a=" + a + ";b=" + b );
}
}
测试类:
package org.joea.classinit;
public class Test {
static int temp;
static{
temp=10;
System.out.println("Test:static block has been initialized!");
}
public static void main(String[] args){
new SubClass().print();
}
}
我们来看一下输出的结果:
Test:static block has been initialized!
SuperClass:static block has been initialized!
SubClass:static block has been initialized!
SuperClass:a=0;b=2;c=3
SubClass:a=0;b=2
从上面的输出结果我们可以看出,还有main函数的类优先初始化;超类的初始化优先于子类;静态域的初始化优先于非静态域;
以上。