类加载
分为依次是 加载、连接、初始化。其中连接又分为(验证,准备,解析三个阶段)
类加载的过程
1.加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
通过一个类的全限定名来获取定义此类的二进制字节流
该动作在Java虚拟机的外部,让程序应用自己决定,如何获取这个类
实现这个动作的程序的叫做类加载器
类加载器由浅到深依次是“应用类加载器”,“扩展类加载器”,“启动类加载器 ”
当类加载器收到加载类的请求时他会先将请求发给父类,层层向上,若最上层启动类加载器无法加载时,才会向下传递请求,下层加载器会依次尝试,这就是双亲委派机制。
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口
2.验证:确保加载的信息符合JVM规范,没有安全方面问题
3.准备:正式为类变量(static)分配内存并设置类变量默认初始值阶段,这些内存都将在方法区中进行分配
4.解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
5.初始化:①执行类构造器()方法的过程,类构造器()方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的(类构造器是构造类信息的,不是构造该类对象的构造器)②当初始化一个类时,如果发现其父类还没有初始化,需对其进行初始化,③虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
类何时被加载
主动引用时用:
1.new新建对象时父类会先被加载,子类之后加载
2.反射调用会被加载
3.调用类的静态成员或方法时被加载
4.main函数所在的类会先被加载
package reflection;
public class ClassInitialization {
//main函数所在的类会先被加载
static {
System.out.println("main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//用new新建对象时父类会先被加载,子类之后加载
// new S();
//反射调用会被加载
//Class.forName("reflection.F");
//调用类的静态成员或方法时被加载
System.out.println(F.a);
}
}
class F{
static int a=1;
static {
System.out.println("父类被加载");
}
}
class S extends F{
static {
System.out.println("子类被加载");
}
}