Java类定义
Class文件是一组以8位字节为基础的二进制流,各个数据之间紧凑判断
Class文件是一种类似于C语言结构体的伪结构存储数据,伪结构只有两种数据类型:无符号数和表
Class文件本质是一张数据表
class文件格式如图
类加载
类加载生命周期:
触发类初始化的几种方式(有且仅有):
- new,getstatic,putstatic 或 invokestatic字节指令时(注意用子类引用父类static变量,不同虚拟机可能稍有差异,这个具体看虚拟机配置,有的会触发子类加载,有的不会)
- 使用使用反射对类进行调用
- 当子类初始化,发现父类未初始化触发父类初始化
- 当虚拟机启动,指定的执行主类(即包含main方法的那个类)
- MethodHandle动态代理触发类加载
加载(loading):
1. 通过一个类的全限定名来获取定义此类的二进制字节流
2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3. 在Java堆中生产一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口
校验(Verfication):
1. 文件格式的验证
2. 元数据验证
3. 字节码验证
4. 符号引用验证
准备(Preparation):正式为类变量分配内存并设置初始值
解析(Resolution):是将常量池内符号引用转为直接引用(变量引用在他自己及父类中递归搜索,匹配到就返回)
初始化(Initialization):初始化阶段是执行类构造器()方法
Class加载(双亲委托模式):
主要类
- BootstrapClassLoder
- ExtensionClassLoader
- AppClassLoader
双亲委托加载关键代码:
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//检查请求的类是否已经加载过了
Class c = findLoadedClass(name);
if(c == null){
try {
ClassLoader parent = getParent();
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
}catch (ClassNotFoundException e){
//如果父类加载器异常抛出 ClassNotFoundException
//则说明父类无法完成加载
}
if(c==null){
//父类无法完成加载
//调用自己的findClass方法来进行加载
c = findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}
注意:虽然我们可以在loadClass完成类加载,但是在JDK1.2以后,虚拟机推荐重写findClass()方法,loadClass()方法的逻辑里如果父类加载失败,则调用自己的findClass()方法