范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

JVM类加载过程

  Java 虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这个过程被称作虚拟机的类加载机制。
  与那些在编译时需要进行连接的语言不同,在 Java 语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的,这种策略让 Java 语言进行提前编译会面临额外的困难,也会让类加载时稍微增加一些性能开销, 但是却为 Java 应用提供了极高的扩展性和灵活性,Java 天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。例如,编写一个面向接口的应用程序,可以等到运行时再指定其实际的实现类,用户可以通过 Java 预置的或自定义类加载器,让某个本地的应用程序在运行时从网络或其他地方上加载一个二进制流作为其程序代码的一部分。这种动态组装应用的方式目前已广泛应用于Java 程序之中,从最基础的 Applet、JSP 到相对复杂的 OSGi 技术,都依赖着 Java 语言运行期类加载才得以诞生。
  之前写的 Java 实战案例:Java 类隔离应用:多 Jar 包支持,就是充分利用了 Java 这个特性实现的。
  在正式学习下面内容之前,避免因表达而造成的歧义,约定如下内容:类型:后文中提到类型,指类或接口,如果需要精确表达类或接口,会特意说明Class 文件:并非只磁盘中编译后的 Class 文件,而是二进制字节流,可能是从磁盘文件读取,也可能是网络、数据库、内存或动态生成的等
  对于类加载过程,包括加载、连接、初始化三个阶段,每个阶段的作用简单概括如下:
  类加载过程三个阶段要注意类加载过程和类加载阶段两个名词的区别:
  类加载过程:是类加载的整个流程,包括加载阶段、连接阶段、初始化阶段
  类加载阶段:只是类加载过程的第一个阶段加载阶段
  在加载阶段,JVM 需要完成下面三件事:通过一个类的全限定名来获取定义此类的二进制字节流将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口
  类加载的最终产物就是堆内存中的 Class 对象,对于同一个 ClassLoader 来说,不管某个类被加载多少次,对应到堆内存中,只有一个 Class 对象。如下图所示:
  虚拟机规范要求类的加载通过类的全限定类名来获取二进制字节流,并没有严格规范获取的途径,这就给开发者很大的想象空间,除了我们平时常见的 Class 文件以外,还会有如下几种形式:从ZIP压缩包中读取,这很常见,最终成为日后JAR、EAR、WAR格式的基础从网络中获取,这种场景最典型的应用就是Web Applet运行时计算生成,这种场景使用得最多的就是动态代理技术,在 java.lang.reflect.Proxy 中,就是用了 ProxyGenerator.generateProxyClass() 来为特定接口生成形式为"*$Proxy"的代理类的二进制字节流由其他文件生成,典型场景是 JSP 应用,由 JSP 文件生成对应的 Class 文件从数据库中读取,这种场景相对少见些,例如有些中间件服务器(如 SAP Netweaver)可以选择把程序安装到数据库中来完成程序代码在集群间的分发可以从加密文件中获取,这是典型的防 Class 文件被反编译的保护措施,通过加载时解密 Class 文件来保障程序运行逻辑不被窥探......连接阶段 - 验证
  验证是连接阶段的第一步,这一阶段的目的是确保 Class 文件的字节流中包含的信息符合《Java虚 拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。
  验证阶段大致会完成下面四个阶段的验证动作:文件格式验证:验证字节流是否符合Class文件格式的规范, 并且能被当前版本的虚拟机处理元数据验证:对字节码描述的信息进行语义分析, 以保证其描述的信息符合《Java语言规范》 的要求字节码验证:整个验证过程中最复杂的一个阶段, 主要目的是通过数据流分析和控制流分析, 确定程序语义是合法的、 符合逻辑的符号引用验证:校验行为发生在虚拟机将符号引用转化为直接引用的时候, 这个转化动作将在连接的第三阶段——解析阶段中发生
  该阶段开发者可控性弱,而且对我们学习 Java 开发意义不大,再次不多赘述,想要更详细的学习具体每阶段验证的内容,可以阅读《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明》连接阶段 - 准备
  在准备阶段,会为类中定义的类变量(即静态变量,使用 static 修饰的变量)分配内存并设置类变量初始值,从概念上讲,这些变量所使用的内存都应当在方法区中进行分配,但必须注意到方法区本身是一个逻辑上的区域,在JDK 7 及之前,HotSpot 使用永久代来实现方法区时,实现是完全符合这 种逻辑概念的;而在 JDK 8 及之后,类变量则会随着 Class 对象一起存放在 Java 堆中,这时候"类变量在方法区"就完全是一种对逻辑概念的表述了。
  需要注意区分类变量和实例变量两个概念:类变量:是被 static 修饰的成员变量,准备阶段分配内存、设置初始值的就是这些变量实例变量:没有被 static 修饰的成员变量,这些变量是在类实例化时,随着对象的创建一起分配内存到堆中
  在此阶段,类变量设置初始值包括两种情况:
  1、编译后 value 具有 ConstantValue 属性
  当类变量是使用 static 和 final 修饰,并且代码中赋值类型为基本数据类型或字符串(这里的字符串是双引号赋值,不是 new String()),如下所示:public class Demo { 	// 基本数据类型     private static final int NUM = 10; 	// 字符串     private static final String STR = "字符串"; }
  使用命令 javap -v -p Demo.class 查看编译后的 Class 文件,如下所示:// 省略 {   private static final int NUM;     descriptor: I     flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL     ConstantValue: int 10    private static final java.lang.String STR;     descriptor: Ljava/lang/String;     flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL     ConstantValue: String 字符串    // 省略 } SourceFile: "Demo.java"
  可以看到两个变量均生成了 ConstantValue 属性,对于这种变量,设置初始值就是当前代码中设置的值。
  2、不具有 ConstantValue 属性
  当类类变量只使用 static 修饰,或使用 static 和 final 修饰,但代码中赋值类型为引用数据类型,如下所示:public class Demo { 	// 只有 static 修饰     private static int num = 10; 	// 赋值为引用数据类型     private static final String STR = new String("字符串"); }
  使用命令 javap -v -p Demo.class 查看编译后的 Class 文件,如下所示:// 省略 {   private static int num;     descriptor: I     flags: (0x000a) ACC_PRIVATE, ACC_STATIC    private static final java.lang.String STR;     descriptor: Ljava/lang/String;     flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL    // 省略 } SourceFile: "Demo.java"
  这类类变量没有生成 ConstantValue 属性,对于这类变量,设置初始值就是对应类型的默认初始值,比如类变量 num 初始值为 0,STR 初始值为 null,具体如下:
  各种数据类型初始化零值连接阶段 - 解析
  该阶段开发者可控性弱,而且对我们学习 Java 开发意义不大,再次不多赘述,想要更详细的学习具体每阶段验证的内容,可以阅读《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明》初始化阶段
  类的初始化阶段是类加载过程的最后一个步骤,之前介绍的几个类加载的动作里,除了在加载阶段用户应用程序可以通过自定义类加载器的方式局部参与外,其余动作都完全由Java虚拟机来主导控制。直到初始化阶段,Java 虚拟机才真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。
  在初始化阶段,最主要做一件事,就是执行类构造器 () 方法(clinit:class initialize 前几个字母的简写),该方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并产生的,如下所示:public class InitStageTest {      private static final String STATIC_CONSTANT = "静态常量";      private static String CLASS_VARIABLE = "类变量";          static {         CLASS_VARIABLE = "类变量重新赋值";     } }
  对上面的类进行编译,执行命令 javap -v -p InitStageTest.class  查看字节码,如下所示:// 省略上面内容 {   private static final java.lang.String STATIC_CONSTANT;     descriptor: Ljava/lang/String;     flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL    private static java.lang.String CLASS_VARIABLE;     descriptor: Ljava/lang/String;     flags: ACC_PRIVATE, ACC_STATIC    public com.haichun.jvm.InitStageTest();     descriptor: ()V     flags: ACC_PUBLIC     Code:       stack=1, locals=1, args_size=1          0: aload_0          1: invokespecial #1                  // Method java/lang/Object."":()V          4: return       LineNumberTable:         line 6: 0       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       5     0  this   Lcom/haichun/jvm/InitStageTest;    static {};     descriptor: ()V     flags: ACC_STATIC     Code:       stack=3, locals=0, args_size=0          0: new           #7                  // class java/lang/String          3: dup          4: ldc           #9                  // String 静态常量          6: invokespecial #11                 // Method java/lang/String."":(Ljava/lang/String;)V          9: putstatic     #14                 // Field STATIC_CONSTANT:Ljava/lang/String;         12: ldc           #20                 // String 类变量         14: putstatic     #22                 // Field CLASS_VARIABLE:Ljava/lang/String;         17: ldc           #25                 // String 类变量重新赋值         19: putstatic     #22                 // Field CLASS_VARIABLE:Ljava/lang/String;         22: return       LineNumberTable:         line 8: 0         line 10: 12         line 13: 17         line 14: 22 } SourceFile: "InitStageTest.java"
  上面输出的信息中 static {} 其实就是  方法
  为了更加直观的看到,可以使用 IDEA 插件 jclasslib Bytecode Viewer 查看类的字节码信息,如下所示:
  根据  方法的字节码可以看到,在该方法中有如下内容:【0 - 9】静态常量赋值(除了静态常量的值可以在编译器确定的以外,这类变量具有 ConstantValue 属性,在连接阶段 - 准备阶段赋值完成,其他类变量只是赋值为默认零值)【12 - 14】类变量赋值【17 - 19】执行静态代码块。
  通过插件可以看到另外一个方法 (对应 javap 命令打印的 public om.haichun.jvm.InitStageTest()),该方法为实例构造器,该方法是在类实例化时调用。要区别  方法, 方法为类构造器,是在类加载过程初始化阶段调用。
  实例构造器,其实就是我们代码中定义的构造函数,如果有多个构造函数,就会有多个 方法。
  方法与  方法不同的是,不需要显示的调用父类类构造器( 方法首先会调用父类实例构造器,如 public om.haichun.jvm.InitStageTest() 命令中 1: invokespecial #1 调用 Object 的构造器),而是由 JVM 保证子类  方法执行前,父类的先执行完成,因此,JVM 第一个执行的 方法的类型一定是 Object。
  由于父类  方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作,因此下面示例中字段 B 的值将会是 2 不是 1:static class Parent {     public static int A = 1;          static {     	A = 2;     } }  static class Sub extends Parent {     public static int B = A; }  public static void main(String[] args) {     System.out.println(Sub.B); }
  方法对于类或接口来说并不是必需的,如果一个类中没有静态语句块,也没有对变量的赋值操作,那么编译器可以不为这个类生成 方法。
  接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成  方法。但接口与类不同的是,执行接口的  方法不需要先执行父接口的  方法,因为只有当父接口中定义的变量被使用时,父接口才会被初始化。此外,接口的实现类在初始化时也一样不会执行接口的 方法。
  参考文献
  深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明
  Java高并发编程详解:多线程与架构设计

外国新能源的对决!福特VS特斯拉究竟谁更值得买?如果是在以往,消费者花30万买车,目光往往会放在传统豪华品牌的燃油车上,当然现在也有很多用户也会这样做,但是自从新源车异军突起,越来越多的用户将目光瞄准了这类车型,除了政策福利外,重温山村老尸,果然有不少值得思考的地方,童年阴影名不虚传我了解,这是很多小宝贝的童年阴影,所以很贴心的P了一张图,希望能缓解你的紧张感。这片子是1999年出的,我第一次看的时候已经是2008年,并没有留下什么太深的印象,我很难理解为何很宝宝裹膜而出近日,怀化市第一人民医院产科诞生了一对孕36周双胞胎的宝宝,出生时还裹着一层保护膜。她们以这样奇特方式降生,其实是医生有意为她们穿上的保护膜。当天早上9点多,在科主任张远方的带领下抵制低俗,正能量诗歌之九数千年农民默默奉献,地位卑微食不果腹,今日麦芒,愿天下农人在希望的田野上,枕着星光梦想富裕成真。麦芒所愿望窗听雨栀子花开,麦芒飘香裹着湿气。清茶怡然着雅人,农人汗水在烈日中氤氲。陇遗精正常吗?快看这里女性在睡眠过程中或者性刺激下,阴道分泌物大量增加有粘液排出,但一般不会被注意,而男性则不同,很多男性朋友因遗精来就诊,忧心忡忡,担心是不是自己身体出现了病变?会不会影响自己的生育能北上广富婆圈一身名牌,全是A货大家好,又到周五。欢迎回来D姐的时尚频道上周,我们聊了LV专柜售假的事,不少姐妹cueD姐聊聊奢侈品高仿。那么今天直接就来到底有多少富婆名媛背假包?奢侈品假货市场有多大?假包能有多凡人修仙传庆祝播放量破八亿,但却被路人群嘲,这是为何?目前小说改编的动漫很多,其中不乏精品之作,比如斗破苍穹凡人修仙传等,最近某站庆祝凡人播放量突破八亿,但实则反观凡人粉丝并不高兴,并且还有其他人进行嘲讽,说这点播放量单集不过一千万,全系降价的奥迪Q7真的太香了,外观大气,内饰豪华,2。0T动力强劲奥迪Q7终于迎来了大降价,作为奥迪的旗舰SUV,在国内市场是很有地位和资历的,更是豪华SUV的标杆级车型,不仅性能出众,而且口碑扎实,是很多男人的努力的目标,在新车上市后价格也有了香港汇丰及恒生两大银行的网上系统出现故障,绝对不能等闲视之文谢悦汉香港汇丰银行及恒生银行的网上系统昨早一度出现故障,数码银行及自动柜员机服务受到影响,又适逢昨日是赛马日,令到很多马迷抱怨和不快。作为全港两大银行(恒生是汇丰属下银行)及市民苹果将在明日凌晨正式发布iOS16系统据国外媒体报道,苹果(AAPL。US)将在6月7日凌晨1点正式发布iOS16系统,发布前夕其公布了一组最新数据,在过去四年推出的设备中,iOS15的普及率达到了89,表现远超分析师距终止上市仅剩1天!退市西水10cm涨停,上交所出手中新经纬6月6日电6日晚间,上交所官方微博发布关于退市西水股票异常交易情况的通报称,6月6日,退市西水股票价格出现异动,个别投资者在交易过程中存在拉抬股价以涨停价大额申报等影响市场
明天!明天!毕业典礼,不见不散!毕业典礼倒计时1天蝉鸣烈日彼时的盛夏终究如约而至又是一年毕业季初入满井的我们憧憬胜过忐忑豪情凌于青涩这一路,我们携手并肩用汗水和泪水写下欢笑荣耀用遗憾和收获填满青春时光如今,我们即中国小麦丰收为国际市场传递积极预期央视网消息受新冠肺炎疫情等因素影响,近两年来,全球粮食价格大幅上涨。那么,中国小麦丰收为国际市场带来什么影响?联合国粮农组织官员表示,中国粮食产量连续7年稳定在1。3万亿斤以上,在油价创1个月新低!今天6月23日全国油价调整后92号95号汽油价格今天是2022年6月23日星期四,国际油价大跌!北海布伦特原油价格作为国内油价调整的重要参考指标结束了连续2个交易日的反弹行情,今天油价大幅下跌创下最近一个月以来新低,在美国市场交映客改名,腾讯下手,元宇宙掀起大流行撰文财经天下周刊作者倪毓平编辑董雨晴作为千播大战时代的佼佼者,映客和它背后的掌舵者奉佑生似乎永远在追风。这一次入局元宇宙亦如是。但相比于押注新社交,元宇宙看上去更像是一个无底洞。自S28赛季更新首日,孙尚香被屏蔽,只因1个原因,玩家秒换木兰典藏王者荣耀S28赛季更新首日,玩家在段位继承后,开启了新一轮的排位征程。而每次大版本更新都会出现异常BUG,S28也不例外!比如参与对局选择孙尚香后,匹配Loading时会出现资源损83年严打大案唐山菜刀队说到76年唐山大地震,我想大家都印象比较深刻,而这次天灾不仅给当地的经济和民生带去了严重的灾难,同时也对之后很长一段时间的唐山社会造成了影响。今天咱们就来聊聊那个特定的时代遇到重大多地规定房价跌幅不能超15,限跌令让房企进退两难又有一地出台楼市限跌令政策。日前,福州市平潭综合实验区四部门联合发布关于进一步规范实验区商品房销售市场秩序的通知。通知提出,各房地产开发企业在销售商品住房时,实际销售价格不得超出备抗日时期这两人在山东矛盾重重,一道调令,成就了一对传奇将帅在抗日战争时期,山东根据地无论在总人口党员军队,还是歼敌人数等方面,都是我党几大根据地中的佼佼者,到1945年8月,山东军区进行了一次整编,主力部队共有八个主力师,后来衍生出解放战CBA三消息山东开启清理计划,高登不想留福建,邢志强确认续约大家好呀,我是北柠,各位小伙伴们要养成先赞后看的习惯哦!山东队是现在CBA联赛中的一支中游水平球队,最近几个赛季关注山东队的球迷们应该都能够清楚感受到球队存在的问题,他们的球员阵容国际原油暴跌,6月28日24时国内很可能迎来2022年第二次油价下调我们来分析一下我国成品油价格的组成部分国内成品油价格构成成本及炼油利润占37。29,政府各种税收占到了成品油价的48。15,其他运营销售成本利润占到14。56。如果你一年加了一万元芯片人才之渴何解从10年不涨薪到应届生年薪五六十万集成电路产业是引领新一轮科技革命和产业变革的关键力量。2021年,我国芯片设计企业已超2800家,但火热的半导体行业却遭遇人才缺口。澎湃新闻在集成电路人才状况调查中发现,当前国内芯