编写的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. html--前端基本标签内容讲解

    body里面分为两类标签:块级标签和内联标签. 1.块级标签:<p><h1><table><ol><ul><form><d ...

  2. [Algorithm] 202. Happy Number

    Write an algorithm to determine if a number is "happy". A happy number is a number defined ...

  3. Python面向对象 | isinstance和issubclass

    isinstance(a,b):判断a是否是b类(或者b类的基类)实例化的对象 class A: pass class B(A): pass obj = B() print(isinstance(ob ...

  4. Pandas | 08 重建索引

    重新索引会更改DataFrame的行标签和列标签. 可以通过索引来实现多个操作: 重新排序现有数据以匹配一组新的标签. 在没有标签数据的标签位置插入缺失值(NA)标记. import pandas a ...

  5. ESA2GJK1DH1K基础篇: 关于各大物联网平台的MQTT通信

    前言 这节稍微唠叨点 其实我很长时间都没有出怎么连接现成的物联网平台的教程, 一直写的是教给大家自己搭建服务器,主要原因是因为我感觉连接现有的学不到东西. 现在出这种教程,是因为发现确实很多人喜欢用. ...

  6. 关于codeforces加载慢

    昨天cdx报名cf,打开网页10多分钟才交了.... 今天问了wxy,百度了一下,以前也搜过,然后就忘记了. 今天记一下.  1.右键单击开始按钮,打开资源管理器,在资源管理器的地址栏中填写" ...

  7. 奇技淫巧and板子

    目录 求第\(k\)大的数 求长度不小于L的子段使之和最大 ST表 \(O(1)\)实现能查询栈中最小元素 二分 树和图的深度优先遍历和广度优先遍历 树的dfs序 求树的重心 图的联通块划分 拓扑排序 ...

  8. PATA1005Spell It Right

    考虑输入为0的特殊情况 参考代码: #define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<cstring> #in ...

  9. TensorFlow分布式训练MNIST分类器

    http://c.biancheng.net/view/2004.html 本节以分布式方式训练完整的 MNIST 分类器. 该案例受到下面博客文章的启发:http://ischlag.github. ...

  10. iptables 的几个状态

    iptables的状态跟踪连接有4种,分别是:NEW.ESTABLISHED.RELATED.INVALID,除了从本机出去的数据包有NAT表的OUTPUT链处理外,其它所有的状态跟踪都在NAT表中的 ...