注:这是参考一些博客自己的学习总结有有问题的地方希望大家指点
类的加载
1.什么是类的加载
类的加载是指把.class结尾的文件以二进制存储在内存中,将其放在运行时的数据区方法区而堆中也会生成一个对象这也就是我们平时反射操作的对象,堆中的对象是我们操作方法区数据结构的提供接口。
类的生命周期
image其中类的加载主要是前五个阶段,在这五个阶段中除了解析,其他的步骤的顺序都是确定的,解析通常情况下可以在舒适化阶段之后开始,这几个步骤的进行不是严格按照顺序的通常是一个步骤进行开始会激活另一个步骤
加载
第一阶段的任务主要是把.class文件编译成二进制的方式存放在虚拟机中,主要完成一下三件事
- 通过类名定义期二进制字节流
- 将字节流转换为运行时数据结构放在方法去
- 在java堆中生成一个代表这个类的java.lang.Class对象,作为访问方法去的入口。反射中操作的就是这个。
在加载阶段我们可以定制自己的类加载器来完成加载
验证
确保类的正确性
有时候为了效率我们可以采用-Xverifynone来关闭大部分验证措施,缩短类加载的时间
准备
为类的静态变量分配内存,并将其初始化为默认值,放在方法去中方法区在某种情况下也被叫做永久代。后面我们会讨论注意两点
- 这个时候我们并不分配实例变量,实例变量会和在初始化阶段分配在堆中
- 这里初始化的(static)变量也不是真正的赋值,通常来讲是赋予一些默认值如(0,null,false)等而真正的赋值也是在运行阶段才会赋值。
- 在final声明的数据时就可以直接在准别阶段赋值如 :private static final int=3
解析
主要功能是把符号引用转变为直接引用。这里引入两个概念直接引用和符号引用
- 符号引用:编译时java并不知道引用类的实际地址,因为还没有真正的加载,这个时候java会以一些无歧义的字面量来对引用类进行加载
- 直接引用:就是传统意义上的引用,直接指向目标指针
初始化
初始化主要就是变量赋值,有两种主要的方式:
- 声明时直接赋予初始值
- 使用static在静态块中给类变量指定出事值
结束生命周期
- 执行System.exit()方法
- 程序正常执行结束
- 异常终止
- java虚拟机终止
类加载器
谈类加载器之前先给大家看一张图
启动定制类: Bootstrap ClassLoader负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的。
扩展类加载器: Extension ClassLoader 该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.开头的类),开发者可以直接使用扩展类加载器。
应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
应用程序通常在这三个类加载器的配合下进行加载。但是类加载器具有局限性,只能加载本地的javaclass文件,我们可以通过编写自己的ClassLoader来实现
- 1.动态地创建符合用户特定需要的定制化构建类。
- 动态地创建符合用户特定需要的定制化构建类。
JVM类加载机制
- 全盘负责 如果一个类加载某个Class,那么该Class依赖和引用的其他类也由他来载入,除非显示的需求其他类来加载
- 父类委托 先让父类加载器加载,父类处理不了才自己尝试
- 缓存机制 加载过的类会被缓存,需要时直接到缓存区去取,只有缓存区不存在才回去加载该类
类的加载
- 通过启动应用时候jvm加载
- 通过Class.forname加载
- 通过ClassLoader.loadClass方法加载
Class.forName()和ClassLoader.loadClass()区别 - Class.forName() 会对类进行,加载到jvm,解释,并且会执行static中的内容(准备)
- ClassLoader.loadClass只会把类加载到jvm中,对static内容执行,需要等到newInstance才会去执行
- Class.forName(name,initialize,loader)也可以指定参数,是否加载static块
双亲委派机制
简单来解释下,就是甩锅机制,当一个加载类的任务来的时候,子类(技术总监)不会亲自去做,会分配给父类(职员),如果父类还有父类就向上甩锅,当没有自己的父类没办法完成的时候(这里代表他的爷爷也没办法完成)才会自己去做。如果最先接到任务的子类都没办法完成,那么就会抛出异常ClassNotFoundException
双亲委派的意义:
- 系统类防止内存中唇线多份同样的字节码
- 保证java程序安全稳定进行
网友评论