类型生命周期开始
装载(将该二进制形式的java类型读入java虚拟机) --> 连接(分为三个步骤,验证(确认java类型数据格式正确且适于java虚拟机使用),准备(为类型分配内存),解析(将常量池中的符号引用转换为直接引用)) --> 初始化(类型初次使用或子类被初始化)
装载
通过该类型的完全限定名,产生一个代表该类型的二进制数据流;解析二进制数据流为方法区的内部数据结构,创建一个表示该类型的java.lang.Class类的实例
连接
验证
检查魔数,确保每一个部分都在正确的位置拥有正确的长度等,确保出Object外每一个类都有一个超类;等方法,类格式正确
准备
解析
在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引用的过程
初始化
先初始化父类,然后执行类初始化方法,执行类变量初始化语句和类型的静态初始化语句,这两个语句被java编译器收集放到一个特殊的方法中,成为类初始化方法<clinit>,只能被虚拟机调用。如果不存在类变量和静态初始化语句或者仅包换static final变量的初始化语句(编译时常量表达式)或者存在类变量但是没有使用静态初始化语句,都不会产生<clinit>,首次使用时也不会执行类初始化。
class Dog{ static final String greeting = "world"; static{ System.out.println("hello'); } } Class Example{ public static void main(String[] args){ System.out.println(Dog.greeting); } }
输出: world
说明类Dog并没有执行类初始化
接口中的public,static,final字段必须在字段初始化语句中初始化,如果接口包含任何在编译时被解析成为一个常量的字段初始化语句,接口就会拥有一个clinit方法
interface Examplelf{ int ketchup=5; int ustard=(int)(Math.ramdom()*0.5); }
java编译器会为上述interface生成一个clinit方法,而只有ustard在clinit中初始化,因为ketchup被初始化为一个编译时常量,而Examplelf.ustard的类型保存指向这个字段的符号引用,使用Examplelf.ketchup的类型会保存5的一份本地copy
类实例化
类构造函数
Class Example{ Example(){ this(1); //调用其他构造函数 } Example(int i){ //默认调用父类的无参数构造函数 } Example(String s){ super();//显示调用父类的构造函数 } }
垃圾收集和对象的终结
由虚拟机回收对象,如果类声明来一个finalize方法,则在释放实例内存前会执行这个终结方法,但是只会调用一次,如果对象复活之后不再被引用,终结方法不会再被调用,且终结方法抛出的任何异常会忽略。
Class example{ protected void finalize(){ } }
卸载类型
启动类装载器装载的类永远是可触及的,不会被卸载,只有用户定义的类装载起装载的类才可被虚拟机回收。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?