编写的java文件在要真正运行时,会首先被编译成 “.class"结尾的二进制文件,然后被虚拟机加载。那么在虚拟机中一个class文件要成为java实例,需要经历好几个步骤:

  1、装载:装载阶段由三个基本动作完成,要装载一个类型,java虚拟机必须:

  (1)通过该类型的完全限定名,产生一个代表该类型的二进制数据流

  (2)解析这个二进制数据流为方法区内的内部数据结构

  (3)创建一个表示该类型的java.lang.Class的实例

  ***当时用new关键字创建一个对象时,该类的数据结构存放在方法区中,new出的对象存放在堆中

  二进制的数据流可由以下方式产生:

  1、从本地加载一个java class 文件

  2、通过网络上下载一个class文件

  3、从一个zip、jar、或者其他文档中提取class文件 等…

  2、验证:类被装载后,就要准备连接,连接的第一步是验证——确认类型符合java语言规范,并且不会危及虚拟机的完整性。

  类型的检查——确保除了Object之外的每个类都必须有一个超类,并确保该类的所有超类都已经被装载了

  类之间的二进制兼容检查——检查final类不能用于子类、检查final类的方法不能被覆盖、确保子类和超类之间没有不兼容的方法

  ——检查所有的常量池入口相互之间一致

  ——检查常量池中的所有特殊字符串是否符合格式

  ——检查字节码的完整性(最为复杂的一步)

  3、准备:在准备阶段java虚拟机为类变量分配内存,设置默认初始值,但在到达初始化之前,类变量都没有被初始化为真正的初始值。即:我们在类中声明 int a = 3;但在这一步,a的致被赋予类型的默认值 0 int a =0;java虚拟机不支持boolean 类型,在内部,boolean变量会被默认的设置为int类型的0,即初始化成false.

  4、解析:经过验证和准备之后,就进入了解析过程。解析就是在类型的常量池中寻找类、接口、字段、以及方法的符号引用,把这些引用替换成为直接引用的过程

  5、初始化:初始化就是赋予一个变量真正的初始值

  如我们定义 private static int a=1; 此时就是给a赋值1

  二、动态链接和解析

  class文件把所有的符号引用保存在——常量池中,每一个 class文件都有一个常量池。每一个被虚拟机装载类或者接口 都有一个内部版本的常量池,被称为运行时常量池。

  常量池的解析——当程序运行时,某个特定的符号引用要被使用, 首先要被解析。解析过程就是根据 符号引用查找到实体, 在把符号引用替换成为 直接引用的过程。每个符号引用都只被解析一次

  早解析——预先解析所有的符号引用,从初始类开始,到后续的各个类,知道所有的符号引用都被解析。

  迟解析——在访问每一个符号引用的最后一刻才去解析。(也可选择两种情况之间的折衷策略)

  ——程序执行都是在第一次 实际访问一个符号引用时才会抛出错误,对于用户来说,看上去都是 迟解析

  ——java虚拟机会把所有具有相同字符串顺序的字符串文字处理成一个String对象。即:如果有多个类使用同一个字符串“Hello”,java虚拟机只会创建一个具有“Hello ”值的String对象 来表示所有的字符串文字。

  ——任何的byte、short、char的值在被压入栈中时, 都会先被转换成int型

  ——涉及byte、short、char的运算操作会首先把他们都转换成int类型,进行计算然后得到int结果,如果需要byte等结果,需要进行显示转换。

  ——java虚拟机中内存只能以对象形式在堆中进行分配,如果需要可考虑基本类型包装器

  ——java所使用的同步机制是监视器,java中的监视器支持两种线程:互斥和协作。java虚拟机是通过锁来实现互斥,是通过Object的wait和notify方法来实现协作

  ——只有当绝对确定等待区中只有一个线程挂起的时候才应使用notify,只要存在同时有多个线程挂起的可能性,就应该使用notify all。否则可能导致某个特定的线程在等待区中等待时间过长,甚至永远就不会苏醒。

  ——堆和方法区是被所有线程共享的

  ——会被多线程访问的两种数据:保存在堆中的实例变量,保存在方法区中的类变量

  ——不需要进行保护的变量:java栈中的局部变量,该数据是拥有该线程的线程私有的

  ——当虚拟机装载一个class文件的时候,会创建一个java.lang.Class类的实例。当锁住一个类的时候,其实就是锁住那个类的Class对象。

  jvm内置的三大类加载器 无锡看妇科哪里好 http://www.xasgfk.cn/

  BootStrap类加载器(BootStrapClassLoader):根类加载器。该加载器没有父加载器,负责加载虚拟机的核心类库,如:java.lang.*等,java.lang.Object就是由根加载器加载的

  Extension 类加载器(ExtClassLoader):它的父加载器为根加载器,也就是上面那个。它从java.ext.dirs系统属性所指定的目录中加载类库,或者从jdk的安装目录jre/lib/ext子目录中加载类库。该类是纯java类是lava.lang.ClassLoader类的子类

  System系统类加载器(AppClassLoader),也称为应用类加载器,其父加载器为扩展类加载器,上面那个。它从环境变量classpath中多指定的目录中加载。它是用户自定义类加载器的默认父加载器,该类是纯java类是lava.lang.ClassLoader类的子类

  **注意:使用Class.forName("com.test.Test1")进行类装载时,会自动执行类中的静态代码块,但不会执行构造方法

  使用loadClass("com.test.Test1")进行装载时,不会自动执行其中的静态代码块,也不会执行构造方法

  ***:同一个类,由两个不同的类加载器去加载,会被认为是两个不相同的类,在方法区中会有两份该类的类信息

  只有使用启动类加载器加载的类,比如:java.lang.Strong、java.lang.Object 等类,在方法区中只有一份类信息。

  判断两个类是否相等的基础是,这两个类的类加载器是不是同一个

  初始化:对于类的初始化阶段,虚拟机规范规定了5种情况下必须立即对类进行初始化

  1、遇到new、getstatic、putstatic、invokestatic这四条字节码指令时,如果类之前没有进行过初始化会进行初始化。这四条字节码对应的是:new 实例、静态字段取值、静态字段赋值、静态字段调用。

  2、使用java.lang.refleat包的方法进行反射调用

  3、当初始化一个类时,如果发现其父类还没有被初始化,需要先初始化其父类

  4、当虚拟机启动,需要执行main方法的类

  5、当使用LDK1.7的动态预言支持时,如果一个java.lang.invole.MethodHandle实例的最后解析结果是REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄。

  以下几种情况需要注意:

  1、对于静态字段,只有直接定义这个字段的类或者接口才会被初始化,如果是通过子类引用父类中的静态字段,只会触发父类的初始化。

  2、常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义类的常量,因此不会触发定义常量的类的初始化。备注:只有编译器能确定之的常量才会进行该操作,编译器无法确定的常量值,还是会触发目标类的初始化。

  例如:public static final String uuid = UUID.randomUUID().toString(); 这行代码,当其他类在引用uuid时,会触发定义该uuid的类的初始化

  3、通过数组定义来引用类,不会触发类的初始化 例如: Super[ ] s = new Super[10]; 这行代码并不会触发Super类的初始化

  4、当一个接口初始化的时候,并不要求其父接口也被初始化,只有真正使用到父接口的时候才会初始化。

  -XX:+TraceClassLoading 查看虚拟机类加载情况

  编写的java文件在要真正运行时,会首先被编译成 “.class"结尾的二进制文件,然后被虚拟机加载。那么在虚拟机中一个class文件要成为java实例,需要经历好几个步骤:

  1、装载:装载阶段由三个基本动作完成,要装载一个类型,java虚拟机必须:

  (1)通过该类型的完全限定名,产生一个代表该类型的二进制数据流

  (2)解析这个二进制数据流为方法区内的内部数据结构

  (3)创建一个表示该类型的java.lang.Class的实例

  ***当时用new关键字创建一个对象时,该类的数据结构存放在方法区中,new出的对象存放在堆中

  二进制的数据流可由以下方式产生:

  1、从本地加载一个java class 文件

  2、通过网络上下载一个class文件

  3、从一个zip、jar、或者其他文档中提取class文件 等…

  2、验证:类被装载后,就要准备连接,连接的第一步是验证——确认类型符合java语言规范,并且不会危及虚拟机的完整性。

  类型的检查——确保除了Object之外的每个类都必须有一个超类,并确保该类的所有超类都已经被装载了

  类之间的二进制兼容检查——检查final类不能用于子类、检查final类的方法不能被覆盖、确保子类和超类之间没有不兼容的方法

  ——检查所有的常量池入口相互之间一致

  ——检查常量池中的所有特殊字符串是否符合格式

  ——检查字节码的完整性(最为复杂的一步)

  3、准备:在准备阶段java虚拟机为类变量分配内存,设置默认初始值,但在到达初始化之前,类变量都没有被初始化为真正的初始值。即:我们在类中声明 int a = 3;但在这一步,a的致被赋予类型的默认值 0 int a =0;java虚拟机不支持boolean 类型,在内部,boolean变量会被默认的设置为int类型的0,即初始化成false.

  4、解析:经过验证和准备之后,就进入了解析过程。解析就是在类型的常量池中寻找类、接口、字段、以及方法的符号引用,把这些引用替换成为直接引用的过程

  5、初始化:初始化就是赋予一个变量真正的初始值

  如我们定义 private static int a=1; 此时就是给a赋值1

  二、动态链接和解析

  class文件把所有的符号引用保存在——常量池中,每一个 class文件都有一个常量池。每一个被虚拟机装载类或者接口 都有一个内部版本的常量池,被称为运行时常量池。

  常量池的解析——当程序运行时,某个特定的符号引用要被使用, 首先要被解析。解析过程就是根据 符号引用查找到实体, 在把符号引用替换成为 直接引用的过程。每个符号引用都只被解析一次

  早解析——预先解析所有的符号引用,从初始类开始,到后续的各个类,知道所有的符号引用都被解析。

  迟解析——在访问每一个符号引用的最后一刻才去解析。(也可选择两种情况之间的折衷策略)

  ——程序执行都是在第一次 实际访问一个符号引用时才会抛出错误,对于用户来说,看上去都是 迟解析

  ——java虚拟机会把所有具有相同字符串顺序的字符串文字处理成一个String对象。即:如果有多个类使用同一个字符串“Hello”,java虚拟机只会创建一个具有“Hello ”值的String对象 来表示所有的字符串文字。

  ——任何的byte、short、char的值在被压入栈中时, 都会先被转换成int型

  ——涉及byte、short、char的运算操作会首先把他们都转换成int类型,进行计算然后得到int结果,如果需要byte等结果,需要进行显示转换。

  ——java虚拟机中内存只能以对象形式在堆中进行分配,如果需要可考虑基本类型包装器

  ——java所使用的同步机制是监视器,java中的监视器支持两种线程:互斥和协作。java虚拟机是通过锁来实现互斥,是通过Object的wait和notify方法来实现协作

  ——只有当绝对确定等待区中只有一个线程挂起的时候才应使用notify,只要存在同时有多个线程挂起的可能性,就应该使用notify all。否则可能导致某个特定的线程在等待区中等待时间过长,甚至永远就不会苏醒。

  ——堆和方法区是被所有线程共享的

  ——会被多线程访问的两种数据:保存在堆中的实例变量,保存在方法区中的类变量

  ——不需要进行保护的变量:java栈中的局部变量,该数据是拥有该线程的线程私有的

  ——当虚拟机装载一个class文件的时候,会创建一个java.lang.Class类的实例。当锁住一个类的时候,其实就是锁住那个类的Class对象。

  jvm内置的三大类加载器

  BootStrap类加载器(BootStrapClassLoader):根类加载器。该加载器没有父加载器,负责加载虚拟机的核心类库,如:java.lang.*等,java.lang.Object就是由根加载器加载的

  Extension 类加载器(ExtClassLoader):它的父加载器为根加载器,也就是上面那个。它从java.ext.dirs系统属性所指定的目录中加载类库,或者从jdk的安装目录jre/lib/ext子目录中加载类库。该类是纯java类是lava.lang.ClassLoader类的子类

  System系统类加载器(AppClassLoader),也称为应用类加载器,其父加载器为扩展类加载器,上面那个。它从环境变量classpath中多指定的目录中加载。它是用户自定义类加载器的默认父加载器,该类是纯java类是lava.lang.ClassLoader类的子类

  **注意:使用Class.forName("com.test.Test1")进行类装载时,会自动执行类中的静态代码块,但不会执行构造方法

  使用loadClass("com.test.Test1")进行装载时,不会自动执行其中的静态代码块,也不会执行构造方法

  ***:同一个类,由两个不同的类加载器去加载,会被认为是两个不相同的类,在方法区中会有两份该类的类信息

  只有使用启动类加载器加载的类,比如:java.lang.Strong、java.lang.Object 等类,在方法区中只有一份类信息。

  判断两个类是否相等的基础是,这两个类的类加载器是不是同一个

  初始化:对于类的初始化阶段,虚拟机规范规定了5种情况下必须立即对类进行初始化

  1、遇到new、getstatic、putstatic、invokestatic这四条字节码指令时,如果类之前没有进行过初始化会进行初始化。这四条字节码对应的是:new 实例、静态字段取值、静态字段赋值、静态字段调用。

  2、使用java.lang.refleat包的方法进行反射调用

  3、当初始化一个类时,如果发现其父类还没有被初始化,需要先初始化其父类

  4、当虚拟机启动,需要执行main方法的类

  5、当使用LDK1.7的动态预言支持时,如果一个java.lang.invole.MethodHandle实例的最后解析结果是REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄。

  以下几种情况需要注意:

  1、对于静态字段,只有直接定义这个字段的类或者接口才会被初始化,如果是通过子类引用父类中的静态字段,只会触发父类的初始化。

  2、常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义类的常量,因此不会触发定义常量的类的初始化。备注:只有编译器能确定之的常量才会进行该操作,编译器无法确定的常量值,还是会触发目标类的初始化。

  例如:public static final String uuid = UUID.randomUUID().toString(); 这行代码,当其他类在引用uuid时,会触发定义该uuid的类的初始化

  3、通过数组定义来引用类,不会触发类的初始化 例如: Super[ ] s = new Super[10]; 这行代码并不会触发Super类的初始化

  4、当一个接口初始化的时候,并不要求其父接口也被初始化,只有真正使用到父接口的时候才会初始化。

  -XX:+TraceClassLoading 查看虚拟机类加载情况

jvm学习笔记之class文件的加载、初始化的更多相关文章

  1. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

  2. Duilib学习笔记《07》— 资源加载

    Duilib的界面表现力能如此丰富,很大程度上得益于贴图描述的简单强大.通过之前的学习及参看相关例子,我们可以发现,在XML布局文件中,不管是窗体背景还是控件,都添加了对应的图片资源以此来美化界面.而 ...

  3. 高性能javascript学习笔记系列(1) -js的加载和执行

    这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的 javascript是解释性代码,解释性代码需要经历转化成计算机指令 ...

  4. easyui学习笔记8—在手风琴中加载其他的页面

    在手风琴中加载其他页面和在表格中加载其他的页面有写类似的,就是请求另外一个页面显示数据. 1.先看看引用的资源文件 <link rel="stylesheet" href=& ...

  5. AppCan学习笔记----关闭页面listview动态加载数据

    AppCan页面关闭 AppCan 的页面是由两个HTML组成,如果要完全关闭的话需要在主HTML eg.index.html中关闭,关闭方法:appcan.window.close(-1); 管道 ...

  6. 【转】ViewPager学习笔记(一)——懒加载

    在项目中ViewPager和Fragment接口框架已经是处处可见,但是在使用中,我们肯定不希望用户在当前页面时就在前后页面的数据,加入数据量很大,而用户又不愿意左右滑动浏览,那么这时候ViewPag ...

  7. HTML之学习笔记(五)图片加载

    Html图片的处理一般采用<img>标签 语法:                例如<img src="地址" />            地址:      ...

  8. 学习笔记TF049:TensorFlow 模型存储加载、队列线程、加载数据、自定义操作

    生成检查点文件(chekpoint file),扩展名.ckpt,tf.train.Saver对象调用Saver.save()生成.包含权重和其他程序定义变量,不包含图结构.另一程序使用,需要重新创建 ...

  9. OpenLayers学习笔记(十)— 动态加载JSON数据模拟航迹线

    在openlayers 3 上,加载本地json数据,动态绘制航迹线,以飞机当前位置为地图中心,此例子是模拟DEMO 本文链接:动态加载JSON数据模拟航迹线 作者:狐狸家的鱼 GitHub:八至 前 ...

随机推荐

  1. 使用 Docker-Compose 编排容器

    我们知道使用一个 Dockerfile 模板文件可以定义一个单独的应用容器,如果需要定义多个容器就需要服务编排.服务编排有很多种技术方案,今天给大家介绍 Docker 官方产品 Docker Comp ...

  2. js 浮点数计算精度不准确问题

    或许很多人都遇到过,js 对小数的加.减.乘.除时经常得到一些奇怪的结果! 比如 :0.1 + 0.2 = 0.3  ? 这么一个简单的计算,当你用js 计算时会发现结果是:0.30000000000 ...

  3. Educational Codeforces Round 78 (Rated for Div. 2) C. Berry Jam

    链接: https://codeforces.com/contest/1278/problem/C 题意: Karlsson has recently discovered a huge stock ...

  4. [SDOi2012]Longge的问题(洛谷 2303)

    题目描述 Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题.现在问题来了:给定一个整数N,你需要求出∑gcd(i, N)(1<=i <=N). 输入格式 一个整数,为N. ...

  5. 使用Java将搜狗词库文件(文件后缀为.scel)转为.txt文件

    要做一个根据词库进行筛选主要词汇的功能,去搜狗下载专业词汇词库时,发现是.scel文件,且通过转换工具(http://tools.bugscaner.com/sceltotxt/)转换为txt时报错如 ...

  6. [算法模板]Kruskal重构树

    [算法模板]Kruskal重构树 kruskal重构树是一个很常用的图论算法.主要用于解决u->v所有路径上最长边的最小值,就是找到\(u->v\)的一条路径,使路径上的最长边最小. 图片 ...

  7. Solr7.x学习(2)-设置开机启动

    1.创建solr用户 useradd solr 2.设置solr-7.7.2目录拥有者 cd /usr/local/ chown -R solr:solr solr-7.7.2 3.在/etc/ini ...

  8. 【C/C++开发】STL内嵌数据类型: value_type

    使用stl库的时候一直对value_type这个东西理解的不是很好,可以说就是不理解.今天看了<STL源码剖析>才恍然大悟.这里稍作记录. 每个STL中的类都有value_type这种东西 ...

  9. kafka作为elk缓存使用

    ELK集群在大规模的日志收集中面临着数据量大,收集不及时,或宕机的风险,可以选择单节点的redis,但是相比redis,kafka集群高可用的特性,更优,下面来配置kafka集群配置elk作为缓存的方 ...

  10. SQLServer --------- 将sql脚本文件导入数据库

    创建数据库方法有两种 第一种通过图形化的操作界面 第二种通过 sql 语句 sql server 如何执行.sql 文件,的原理就是执行sql语句进行创建 打开数据库后找到   最左侧文件 找到需要执 ...