Java 类的初始化

news/2024/11/7 13:43:23/

 类的初始化详细过程

字节码-->加载-->验证-->准备-->解析-->初始化

1)加载:通过类的完全限定名找到类文件所在位置,根据其中的字节码创建java.lang.Class对象,所以才会说万物皆对象,我们也可以继承ClassLoader,重写findClass方法来自定义实现类加载器。默认情况下我们都使用AppClassLoader。

1.通过全类名获取定义此类的二进制字节流

2.将字节流所代表的静态存储结构转换为方法区的运行时数据结构

3.在内存中(对于HotSpot虚拟就而言就是方法区)生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;

2)验证:确保加载的字节码的是否符合虚拟机的要求,是java提供的一种自我保护机制,不让其危害虚拟机安全。其主要包括四种验证,字节码验证、文件格式验证,元数据验证、符号引用验证

3)准备为类变量分配地址和初始化值,类变量会分配到方法区(元空间)中,这里的初始化是指该数据类型的默认初始值,例如int对应的是0,long对应的0L,只有在初始化时才会动显示赋值。实例变量主要随着对象的实例化一块分配到java堆中

4)解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。

--符号引用(在编译时java类并不知道引用类的实际内存地址,因此使用符号引用来代替)就是一组符号来描述目标,可以是任何字面量(理解为自然语言,只需要能无歧义的定位到指示的目标即可)。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。在程序实际运行时,只有符号引用是不够的,举个例子:在程序执行方法时,系统需要明确知道这个方法所在的位置。Java虚拟机为每个类都准备了一张方法表来存放类中所有的方法。当需要调用一个类的方法的时候,只要知道这个方法在方发表中的偏移量就可以直接调用该方法了。通过解析操作符号引用就可以直接转变为目标方法在类中方法表的位置,从而使得方法可以被调用。

综上,解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,也就是得到类或者字段、方法在内存中的指针或者偏移量

5)初始化:主要为类的静态变量赋予正确的值,比如int num = 10; 这里num的值会从准备阶段的0变为10;并且若该类有父类,会对其进行初始化操作;如果类中有初始化语句,系统会按照顺序进行初始化。

初始化是类加载的最后一步,也是真正执行类中定义的Java程序代码(字节码),初始化阶段是执行类构造器clinit()方法的过程。

初始化过程如下:

 

类加载器的顺序

Java语言系统自带有三个类加载器:

  1. Bootstrap ClassLoader:最顶层的加载类,主要加载核心类库,也就是我们环境变量下面%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。
  2. Extention ClassLoader扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。
  3. Appclass Loader也称为SystemAppClass。 加载当前应用的classpath的所有类。

应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,还可以加入自定义的类加载器

 

Bootstrap ClassLoader > Extention ClassLoader > Appclass Loader

双亲委派机制

当一个类收到了加载请求时,它是不会先自己去尝试加载的,而是委派给父类去完成,比如我现在要new一个 Person,这个 Person 是我们自定义的类,如果我们要加载它,就会先委派 App ClassLoader ,只有当父类加载器都反馈自己无法完成这个请求(也就是父类加载器都没有找到加载所需的 Class)时,子类加载器才会自行尝试加载。

这样做的好处是,加载位于rt.jar包中的类时不管是哪个加载器加载,最终都会委托到BootStrap ClassLoader进行加载,这样保证了使用不同的类加载器得到的都是同一个结果。

其实这个也是一个隔离的作用,避免了我们的代码影响了JDK的代码,比如我现在自己定义一个java.lang.String

尝试运行当前类的 main 函数的时候,我们的代码肯定会报错。这是因为在加载的时候其实是找到了 rt.jar 中的java.lang.String,然而发现这个里面并没有 main 方法。

 


http://www.ppmy.cn/news/806772.html

相关文章

串口初始化配置详解

STC15系列单片机之串口初始化 什么是串口 简单理解就是一个电脑和单片机之间沟通的桥梁,从电脑角度考虑,我要发送信息给单片机,我需要什么,肯定是需要一个数据线对吧,将我要传给单片机的信息通过数据线发送过去&…

swiper基本初始化

Swiper常用于移动端网站的内容触摸滑动 Swiper是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端。 Swiper能实现触屏焦点图、触屏Tab切换、触屏轮播图切换等常用效果。 Swiper开源、免费、稳定、使用简单、功能强大,是架构移动终端网站的…

java-初始化数组

Java 语言中数组必须先初始化,然后才可以使用。所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初始值。 能不能只分配内存空间,不赋初始值呢? 不行,一旦为数组的每个数组元素分配了内存…

pytorch tensor 初始化_PyTorch简明笔记[1]-Tensor的初始化和基本操作

听麻麻说,偷偷收藏而不感谢是不礼貌的,至少应该点个赞~我觉得麻麻说的对! 不断地被人安利PyTorch,终于忍不住诱惑决定入坑了。 当初学习TensorFlow的时候,没有系统性地学习。之前TF的英文官网一直看不了,而中文版的文档又很烂,导致学起来一直不那么爽,每次搭建模型的时…

DMA初始化设置

DMA(Direct Memory Access) ,即直接存储器存取,是一种快速传送数据的机制。数据传递可以从适配卡到内存,从内存到适配卡或从一段内存到另一段内存。 DMA技术的重要性在于,利用它进行数据传送时不需要CPU的参与。每台电脑主机板上都有DMA控制器,通常计算机对其编程,并用一…

c语言中初始化的主要作用,C语言初始化——栈的初始化

栈是一种具有后进先出性质的数据组织方式,也就是说后存放的先取出,先存放的后取出。栈底是第一个进栈的数据所处的位置,栈顶是最后一个进栈的数据所处的位置。 1.满栈与空栈 根据SP指针指向的位置,栈可以分为满栈和空栈 满栈:当堆栈指针SP总是指向最后压入堆栈的数据。 空…

ocr初始化失败怎么办_应用程序正常初始化失败

网民使用电脑中经常遇到因各种原因引起应用程序正常初始化失败,但是网上的方法都很难解决问题,金山安全专家指出,现在很多病毒木马喜欢劫持应用程序和系统文件,会导致出现出错的,请立刻下载金山卫士进行木马查杀。 应用…

云服务器初始化失败怎么办,提示交互式登录进程初始化失败是什么原因?解决方法步骤教程...

平常我们经常会在电脑上安装和卸载应用软件,期间就会遇到win7系统提示交互式登录进程初始化失败这样的事情,相信有太多的用户是不愿意遇到win7系统提示交互式登录进程初始化失败这种情况的,想请高手帮忙解决win7系统提示交互式登录进程初始化…