java没有规定类加载的时机,但是规定了类初始化的时机,一般认为类初始化的时候就加载。
一、类初始化的时机
1.创建类的实例,也就是new一个对象
2.访问某个类或接口的静态变量和静态方法 (直接用类名访问,没有new一个实体对象),注意访问类的静态域所导致的初始化,只初始化这个类,不会初始化这个类的父类。
3.反射(Class.forName(“com.lyj.load”)) 比如类Class中的方法或者java.lang.reflect包的方法对类进行反射调用的时候, 如果类没有进行过初始化 , 则需要先触发其初始化。
4…初始化一个类的派生类(会首先初始化子类的父类),只有在父类还没有初始化的时候,子类初始化才会让父类初始化。注意接口的初始化不会让父接口也初始化。
5.JVM启动时标明的启动类,即文件名和类名相同的那个类
Animal a = new Animal;
System.out.println(Person.name);
System.out.println(Person.shout());
Son s = new Son();
二、类初始化的顺序
初始化顺序有以下几个原则:
1.超类初始化早于子类。
2.静态变量和成员方法初始化早于非静态方法和变量,但是静态域只初始化一次。
3.没使用的类根本不会被初始化,因为他没有被使用
4.在类的加载过程中,只有内部的变量和代码块创建完,才会去执行这个类的构造方法(除了static的方法,其他的方法都是在被调用的时候才会执行,只有构造方法会自己执行,所以等变量和代码块创建完,再调用构造方法加载各种函数)。
注意:这里说的代码块,是类中没有写成方法的代码块,相当于一个default的变量,比如下面例子A中的"A codeblock"那一句。
package test_demo;
public class test_shunxu {
public static void main(String[] args) {
A a = new A();
}
}
class A{
B b = new B();
static{
System.out.println("A static");
}
{System.out.println("A codeblock");}
public A() {
System.out.println("A()");
}
}
class B{
C c = new C();
D d = new D();
static{
System.out.println("B static");
}
public B() {
System.out.println("B()");
}
}
class C{
static{
System.out.println("C static");
}
public C() {
System.out.println("C()");
}
}
class D{
static{
System.out.println("D static");
}
public D() {
System.out.println("D()");
}
}
结果:
A static
B static
C static
C()
D static
D()
B()
A codeblock
A()
package xing.test.thinking.chap7;
class A{
static{
System.out.println("A static");
}
}
class B extends A{
static{
System.out.println("B static");
}
}
class C extends B{
private static D d = new D();
static{
System.out.println("C static");
}
}
class D{
static{
System.out.println("D static");
}
}
public class ExtendTest {
public static void main(String[] args) {
C c = new C();
}
}
结果:
A static
B static
D static
C static
结论1:父类的静态代码块->子类的静态代码块->初始化父类的属性值/父类的普通代码块(自上而下的顺序排列)->父类的构造方法->初始化子类的属性值/子类的普通代码块(自上而下的顺序排列)->子类的构造方法。
结论2:静态资源在类的初始化中只会执行一次。
结论3:在结论2的基础上,非静态资源会随对象的创建而执行初始化。每创建一个对象,执行一次初始化。