在Java代码中,类型的加载,连接和初始化过程都是在程序运行期间完成的
优点:
提供了更大的灵活性
增加了更多的可能性
调用一个类的main方法时,其执行步骤如下:
将二进制形式的java类型
读入JVM中
java.lang.class
对象(规范并未说Class对象位于哪里,HotSpot虚拟机将其放在了方法区中)用来封装类在方法区的数据结构加载.class文件的方式
将Java源文件动态编译为.class文件
类被加载后,就进入到连接阶段—就是将已经读入到内存中的类的二进制数据合并到虚拟机的运行时环境中去
连接包括三个步骤:
静态变量
分配内存,设置默认值, 为类变量分配内存,设置默认值,但是在到达初始化之前,类变量都没有初始化为真正的初始值
例如: 对与以下Sample类,在准备阶段,将为int类型的静态变量a分配4个字节的内存空间,并赋予默认值0,为long类型的静态变量b分配8个字节的内存空间,并且赋予默认值0
即:int
初始化为0,boolean
初始化为false
public class Sample{
private static int a = 1;
public static long b;
static{
b=2;
}
...
}
把类中的符号引用转为直接引用,使用指针的凡是指向目标对象内存地址
在初始化阶段.JVM执行类的初始化语句,为类的静态变量赋予初始值.在程序中,静态变量的初始化有两种途径:
1). 在静态变量的声明处进行初始化
2). 在静态代码块中进行初始化
例如在以下代码中,静态变量a和b都被显示初始化,而静态变量从没有被显示初始化,它将保持默认值0.
public class Sample{
private static int a = 1;
public static long b;
public static long c;
static{
b=2;
}
...
}
静态变量的声明语句,以及静态代码块都被看做类的初始化语句,JVM会按照初始化语句在类文件的先后顺序来依次执行他们.例如以下Sample类被初始化后,它的静态变量a的取值为4
public class Sample{
private static int a = 1;
public static long b;
static{
a = 2;
}
static{
a = 4;
}
public static void main(String args[]){
System.out.println("a="+a);
}
...
}
执行结果为
a=4
所有的JVM实现必须在每个类或接口被Java程序首次使用
是才初始化他们
类的初始化时机
只有当程序访问的静态变量或静态方法确实在类或当前接口中定义时,才可以认为是对类或接的主动使用
重要
)被动使用
,不会导致类的初始化因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量是,才会导致该接口的初始化
调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化
. 针对源代码中每一个类的构造方法,java编译器都产生一个
方法