前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM之类的生命周期(二)

JVM之类的生命周期(二)

作者头像
23号杂货铺
发布2019-09-26 17:38:17
3650
发布2019-09-26 17:38:17
举报
文章被收录于专栏:23号杂货铺23号杂货铺

我们都知道,在Java当中,JVM为Java程序提供运行时环境,其中一项重要的任务就是管理类和对象的生命周期。类的生命周期,简单来说,是从类被加载、连接和初始化开始,到类被卸载结束。

当类处于生命周期中时,他的二进制数据位于方法区内,在堆区内还会有一个相应的描述这个类的Class对象。只有当类处于生命周期中时,Java程序才能使用它,比如调用类的静态属性和方法,或创建类的实例对象。

当启动一个Java进程时,JVM进程从启动、到终止,称为Java虚拟机的生命周期

1、类的加载、连接和初始化

a、加载

I、通过一个类的全限定名来获取其定义的二进制字节流。

II、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

III、在Java堆中生成一个代表这个类的 java.lang.Class 对象,作为对方法区中这些数据的访问入口。

b、连接

I、验证:确保被加载的类的正确性

II、准备:为类的静态变量分配内存,并将其初始化为默认值

默认初始值如下:

1.八种基本数据类型默认的初始值是0

2.引用类型默认的初始值是null

3.有static final修饰的会直接赋值,

例如:static final int x=10;则默认就是10.

III、解析:把类中的符号引用转换为直接引用

c、初始化

I、假如这个类还没有被加载和连接,则程序先加载并连接该类

II、假如该类的直接父类还没有被初始化,则先初始化其直接父类

III、假如类中有初始化语句,则系统依次执行这些初始化语句

类的初始化时机是什么?

JVM只有在程序首次主动使用一个类或者接口时才会初始化。有6种活动被看做是程序对类或接口的主动使用。

1、创建类的实例,可以通过new、反射、clone、反序列化的方式。

2、调用类的静态方法。

3、访问某个类或接口的静态变量,或者对该静态变量赋值。

4、调用Java API种某些反射方法,比如Class.forName("BboyHan"),假如BboyHan类还没有被初始化,那么forName()方式是java.lang.Class类的静态方法。

5、初始化一个类的子类。可以看做是它对父类(或者称为基类)的主动使用,因此会先初始化父类。

6、JVM启动时被标明为启动类的类。如“java Sample”命令,Sample类就是启动类。

除了以上6种情形,其他使用Java类的方式都被看做是被动使用,都不会导致类的初始化。

d、使用

只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:

I、创建类的实例,也就是new的方式

II、访问某个类或接口的静态变量,或者对该静态变量赋值

III、调用类的静态方法

IV、反射(如 Class.forName(“com.shengsiyuan.Test”))

V、初始化某个类的子类,则其父类也会被初始化

VI、Java虚拟机启动时被标明为启动类的类( JavaTest),直接使用 java.exe命令来运行某个主类

e、卸载

I、执行了 System.exit()方法

II、程序正常执行结束

III、程序在执行过程中遇到了异常或错误而异常终止

IV、由于操作系统出现错误而导致Java虚拟机进程终止

2、类加载器

一个类在JVM当中又是如何被加载并使用的呢?

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。

1、当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化:

2、类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。

3、当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。

它有两种装载class的方式:显式和隐式

隐式:运行过程中,碰到new方式生成对象时,隐式调用classLoader到JVM

显式:通过class.forname()动态加载

类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

加载类的过程:采用双亲委托机制(双亲委派模型)

双亲委派模型的工作过程:

a、当前 ClassLoader 首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。

b、当前 classLoader 的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到 bootstrap ClassLoader.

c、当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

思考:如何判定两个 Java 类是相同的?

Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。因此,在判断是否为同一个Java类时,必须是由同一个类加载器所加载。

End......

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 23号杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档