Java类生命周期

java 类生命周期

jvm 运行时内存

运行时内存分5个数据区 方法区、堆区、虚拟机栈、本地方法栈、程序计数器
这在五个数据区分两种类型:
所有线程共享数据区
1.方法区 用于存放类信息、常量、静态变量 常量池位于该区域。
2.堆区 用户存放对象的区域 gc主要是发生在这个区域。

线程私有数据区(每个线程相互隔离)
1.虚拟机栈 方法执行时创建一个栈帧,用于存放局部变量、操作数栈、动态链接、方法出口信息等。每个方法创建一个栈帧,互不干扰。
2.本地方法栈 用于存放执行native 方法的运行数据。
3.程序计数器 当前线程执行的字节码指数器,通过改变指数器来选取下一条执行的字节码指令。

类的生命周期

java文件编译后生产class后缀的问题,一个类的生命周期就是从一个class文件的加载到卸载;
一个类的完整的生命周期经过加载、连接、初始化、使用、卸载五个阶段,也存在一些特殊的情况在连接完成后直接进入使用阶段。示意图如下:

加载

通常的我们讲的类加载是指类进行了加载、连接、初始化三个阶段;
在加载阶段JVM做了一个简单的工作。找到需要加载的类并把类信息加载到JVM的方法区中,同时在堆中实例化一个java.lang.Class对象作为方法区中这个类信息的入口。

类的加载方式灵活多样根据寻找class文件的不同,主要有以下几种
1.根据全路径名找到相应的class文件读取内容
2.直接从jar包中读取内容
3.从网络中获取
4.根据一定的规则实时生成,比如设计模式中的代理模式,根据相应的类自动生成它的代理类
5.从非class文件中获取,本质上与class文件一样,JVM运行前将非class文件转换成可被识别的字节码

类的加载时机 原则:在类使用前对类进行加载 通长两种方式:
1.遇到就加载
2.使用前才加载 (Hotspot使用该种方式)

连接

加载后的验证工作及初始化前的准备工作,主要是细分以下三个步骤
1.验证
主要是验证类的合法性,语法检查,变量检查,继承关系检查等,保证加载的类能被JVM所运行
2.准备
准备阶段为类的静态变量分配内存并设置JVM初始值(特别注意这里是设置JVM的初始值非代码里面定义的初始值,常量除外)非静态的变量不会为他们分配内存。(被static 和final 修饰的 变量 会放入常量池 且初始化值为代码指定的值)
3.解析
将符号引用变成直接引用

初始化

如果一个类被直接引用就会触发类的初始化。java中直接引用的几种情况:
1.通过new关键字实例化一个对象、读取或者设置一个类的静态字段以及调用一个类的静态方法;
2.通过反射调用时如果类还未初始化则对类进行初始化;
3.初始化一个类时发现其父类还没初始化则对父类进行初始化;
4.虚拟机启动时需要指定一个执行的主类,即main方法所在的类;

类初始化的顺序是:静态语句、静态代码块 > 变量、初始化块 > 构造函数 同一级别中按照从上自下的顺序 如果存在父类则优先父类然后子类

class Filed1 {

    public Filed1() {
        System.out.println("Field1 constructor");
    }
}
class Filed2 {

    public Filed2() {
        System.out.println("Filed2 constructor");
    }

}
class Filed3 {

    public Filed3() {
        System.out.println("Field3 constructor");
    }
}

class InitClass2 {

    static {
        System.out.println("InitClass2 static code");
    }

    public static Filed1 filed1 = new Filed1();
    public Filed2 filed2 = new Filed2();

    public InitClass2() {
        System.out.println("InitClass2 constructor");
    }
}
class SubInitClass2 extends InitClass2{
    public SubInitClass2() {
        System.out.println("SubInitClass2 constructor");
    }

    static{
        System.out.println("subInitClass static code");
    }
    public static Filed3 filed3 = new Filed3();
}

public class Test2{
    public static void main(String[] args) {
        new SubInitClass2();
    }
}

输出结果:

InitClass2 static code
Field1 constructor
subInitClass static code
Field3 constructor
Filed2 constructor
InitClass2 constructor
SubInitClass2 constructor

在以上输出的结果中注意Filed2为非静态变量其初始化在静态变量之后

使用

类的使用包括主动引用和被动引用,主动引用见初始化过程。被动引用有以下几种情况:
1.引用父类的静态字段,只会引起父类的初始化而不会引起子类的初始化;
2.定义类数组,不会引起类的初始化
3.引用类的常量不会引起类的初始化

使用阶段包括主动引用和被动引用,主动引用会引起类的的初始化 被动引用不会引起类的初始化。

卸载

类使用完后满足以下条件类就会被卸载
1.该类的所有实例已经被回收,即堆中不存在该类的实例
2.加载该类的ClassLoader 已经被回收
3.该类的java.lang.Class对象没有任何地方引用,即无法通过反射访问到该类的方法

参考连接:
http://www.jianshu.com/p/1579aafac60b
http://blog.csdn.net/zhengzhb/article/details/7517213

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值