详解JAVA类加载机制(推荐)
作者:冬瓜蔡 发布时间:2021-08-10 04:43:10
JAVA源码编译由三个过程组成:
1、源码编译机制。
2、类加载机制
3、类执行机制
我们这里主要介绍编译和类加载这两种机制。
一、源码编译
代码编译由JAVA源码编译器来完成。主要是将源码编译成字节码文件(class文件)。字节码文件格式主要分为两部分:常量池和方法字节码。
二、类加载
类的生命周期是从被加载到虚拟机内存中开始,到卸载出内存结束。过程共有七个阶段,其中到初始化之前的都是属于类加载的部分
加载----验证----准备----解析-----初始化----使用-----卸载
系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行的java程序处于两个不同的JVM进程中,两个jvm之间并不会共享数据。
1、加载阶段
这个流程中的加载是类加载机制中的一个阶段,这两个概念不要混淆,这个阶段需要完成的事情有:
1)通过一个类的全限定名来获取定义此类的二进制字节流。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在java堆中生成一个代表这个类的Class对象,作为访问方法区中这些数据的入口。
由于第一点没有指明从哪里获取以及怎样获取类的二进制字节流,所以这一块区域留给我开发者很大的发挥空间。这个我在后面的类加载器中在进行介绍。
2、准备阶段
这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。
1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中。
2、这里设置的初始值,通常是指数据类型的零值。
private static int a = 3;
这个类变量a在准备阶段后的值是0,将3赋值给变量a是发生在初始化阶段。
3、初始化阶段
初始化是类加载机制的最后一步,这个时候才正真开始执行类中定义的JAVA程序代码。在前面准备阶段,类变量已经赋过一次系统要求的初始值,在初始化阶段最重要的事情就是对类变量进行初始化,关注的重点是父子类之间各类资源初始化的顺序。
java类中对类变量指定初始值有两种方式:1、声明类变量时指定初始值;2、使用静态初始化块为类变量指定初始值。
初始化的时机
1)创建类实例的时候,分别有:1、使用new关键字创建实例;2、通过反射创建实例;3、通过反序列化方式创建实例。
new Test();
Class.forName(“com.mengdd.Test”);
2)调用某个类的类方法(静态方法)
Test.doSomething();
3)访问某个类或接口的类变量,或为该类变量赋值。
int b=Test.a;
Test.a=b;
4)初始化某个类的子类。当初始化子类的时候,该子类的所有父类都会被初始化。
5)直接使用java.exe命令来运行某个主类。
除了上面几种方式会自动初始化一个类,其他访问类的方式都称不会触发类的初始化,称为被动引用。
1、子类引用父类的静态变量,不会导致子类初始化。
public class SupClass
{
public static int a = 123;
static
{
System.out.println("supclass init");
}
}
public class SubClass extends SupClass
{
static
{
System.out.println("subclass init");
}
}
public class Test
{
public static void main(String[] args)
{
System.out.println(SubClass.a);
}
}
执行结果:
supclass init
123
2、通过数组定义引用类,不会触发此类的初始化
public class SupClass
{
public static int a = 123;
static
{
System.out.println("supclass init");
}
}
public class Test
{
public static void main(String[] args)
{
SupClass[] spc = new SupClass[10];
}
}
执行结果:
3、引用常量时,不会触发该类的初始化
public class ConstClass
{
public static final String A= "MIGU";
static
{
System.out.println("ConstCLass init");
}
}
public class TestMain
{
public static void main(String[] args)
{
System.out.println(ConstClass.A);
}
}
执行结果:
MIGU
用final修饰某个类变量时,它的值在编译时就已经确定好放入常量池了,所以在访问该类变量时,等于直接从常量池中获取,并没有初始化该类。
初始化的步骤
1、如果该类还没有加载和连接,则程序先加载该类并连接。
2、如果该类的直接父类没有加载,则先初始化其直接父类。
3、如果类中有初始化语句,则系统依次执行这些初始化语句。
在第二个步骤中,如果直接父类又有直接父类,则系统会再次重复这三个步骤来初始化这个父类,依次类推,JVM最先初始化的总是java.lang.Object类。当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。
以上所述是小编给大家介绍的JAVA类加载机制(推荐),希望对大家有所帮助!
来源:http://www.cnblogs.com/dongguacai/p/5860241.html


猜你喜欢
- 前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷。在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除
- 本文实例讲述了Android实现仿通讯录侧边栏滑动SiderBar效果代码。分享给大家供大家参考,具体如下:之前看到某些应用的侧边栏做得不错
- Android中的Selector的用法 <?xml version="1.0" encoding=&q
- 本文实例为大家分享了Android仿新浪微博分页管理界面的具体代码,供大家参考,具体内容如下多个activity分页管理,为了方便获取上下文
- 项目要求1.初次打开程序时右上角标题栏显示“无连接”,点击旁边的按钮选择“我的好友”,进入配对界面;2.选择好友之后,返回主界面,标题栏会显
- 方法有4种:使用 String 类的 valueOf() 方法使用字符串连接使用 Character 类的 toString() 方法使用字
- 本文实例为大家分享了Java模拟实现斗地主发牌的具体代码,供大家参考,具体内容如下题目:模拟斗地主的发牌实现,54张牌,每张牌不同的花色(红
- 效果图如下:默认第一次加载选择原始队列:级联效果图:关键代码给下拉列表选中事件监听绑定Id :int pos = firsthand_dlb
- springboot加载yml文件获不到值今天使用spring boot读取yml文件,这种多层嵌套的竟然无法读取到(value注解spri
- 一、所需要的包:1、commons-fileupload-1.2.1.jar:下载地址http://commons.apache.org/d
- 本文实例讲述了java生成随机数的方法。分享给大家供大家参考。具体实现方法如下:package com.tool.code; import
- 有项目需求需要绘制多个圆圈,并且使用连续的数字对其排列起来,也就是好多排的圆圈。首先看一下效果图:一排设置为8个,一共有53个的:一排设值为
- 最近开发遇到了个问题,app升级的时候,其他手机都能正常升级,下载完安装包,跳到安装页面进行新版本的安装。但却有用户反映,华为P10和华为M
- 本文主要介绍了25行Java代码将普通图片转换为字符画图片和文本的实现,分享给大家,具体如下:原图生成字符画文本(像素转换字符显示后,打开字
- 从相册或拍照更换图片功能的实现:(取图无裁剪功能)获取图片方式: (类似更换头像的效果)1、手机拍照 选择图片;2、相册选取图片;本文只是简
- 1.修改系统默认的Dialog样式(风格、主题)2.自定义Dialog布局文件3.可以自己封装一个类,继承自Dialog或者直接使用Dial
- 在前端中我们知道用javascript就可以可以很容易实现,那么在Android中怎么实现这个功能呢?Java代码package com.e
- 开发环境使用jdk1.8.0_60,把springboot 项目打成war包后,部署到apache-tomcat-7.0.68时报错如下,换
- 问题描述:使用Design包的TabLayout实现类似网易选项卡动态滑动效果的时候,使用addTab()方法给TabLayout动态添加标
- 建库建表DROP DATABASE IF EXISTS mp;CREATE DATABASE mp DEFAULT CHARACTER SE