一、触发类加载的几种情况:
(1)、调用静态成员时,会加载静态成员真正所在的类及其父类。
通过子类调用父类的静态成员时,只会加载父类而不会加载子类。
(2)、第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)。
(3)、加载子类会先加载父类。(覆盖父类方法时所抛出的异常不能超过父类定义的范围)
注:如果静态属性有 final 修饰时,则不会加载,当成常量使用。
例:public static final int a =123;
但是如果上面的等式右值改成表达式(且该表达式在编译时不能确定其值)时则会加载类。
例:public static final int a = math.PI
如果访问的是类的公开静态常量,那么如果编译器在编译的时候能确定这个常量的值,就不会被加载;
如果编译时不能确定其值的话,则运行时加载
package staticTest;
import java.util.Random;
public class A {
static{
System.out.println("A static block...");
}
public static void main(String[] args) {
//System.out.println(B.a);
System.out.println(B.b);
}
}
class B{
static{
System.out.println("B static block1...");
}
public static final int a=new Random().nextInt(10);
public static final int b=2;
static{
System.out.println("B static block 2...");
}
}
out put:
A static block...
2
所以,调用某类的静态常量时,此类不会加载,但若表达式右边需要计算,则此类会加载。
二、类加载的顺序:
1、先递归地加载父类的静态成员/代码块(Object的最先),再依次加载到本类的静态成员。其中同一个类中的静态成员和静态代码块按编写代码的顺序加载。同一个类中调用方法时,不用理会写代码的顺序。
2、递归加载完父类至本类的静态成员或代码块后,再一次递归加载非静态成员、代码块和构造函数,这三者是一次性递归加载。其中同一个类中的非静态成员、代码块按编写顺序加载,均在构造函数之前加载。
package extendsTest;
public class staticTest{
public static int getInt(int i){
System.out.println(i);
return i;
}
public static void main(String[] args) {
new SmallOrange();
}
}
class Fruits {
private int a=staticTest.getInt(1);
static int a1=staticTest.getInt(11);
static{
System.out.println("Fruits()static");
}
{
System.out.println("Fruitsblock");
}
public Fruits(){
System.out.println("Fruits()constructor");
}
}
class Orange extends Fruits{
{
System.out.println("Orangeblock");
}
static{
System.out.println("Orange()static");
}
static int b1=staticTest.getInt(22);
public Orange(){
System.out.println("Orange()constructor");
}
private int b=staticTest.getInt(2);
}
class SmallOrange extends Orange{
private int c=staticTest.getInt(3);
static int c2=staticTest.getInt(33);
{
System.out.println("SmallOrangeblock");
}
static{
System.out.println("SmallOrange()static");
}
public SmallOrange(){
System.out.println("SmallOrange()constructor");
}
}
//output:
11
Fruits() static
Orange() static
22
33
SmallOrange() static
1
Fruits block
Fruits() constructor
Orange block
2
Orange() constructor
3
SmallOrange block
SmallOrange() constructor
由此我们可以看出,先递归完静态成员或静态块的加载,再递归非静态成员、非静态块、构造函数。其中构造函数再三者中是最后的。