当前位置: 首页 > 编程日记 > 正文

Java虚拟机类加载机制

虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

Java语言里,类型的加载和连接过程是在程序运行期间完成的。

类的生命周期

加载 loading

验证 verification

准备 preparation

解析 resolution

初始化 initialization

使用 using

卸载 unloading

有且只有以下四种情况必须立即对类进行”初始化”(称为对一个类进行主动引用):

  1. 遇到new、getstatic、putstatic、invokestatic这四条字节码指令时(使用new实例化对象的时候、读取或设置一个类的静态字段、调用一个类的静态方法)。
  2. 使用java.lang.reflet包的方法对类进行反射调用的时候。
  3. 当初始化一个类的时候,如果发现其负类没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,虚拟机会初始化主类(包含main方法的那个类)。

被动引用

  1. 通过子类引用父类的静态字段,不会导致子类初始化(对于静态字段,只有直接定义这个字段的类才会被初始化)。
  2. 通过数组定义类应用类:ClassA [] array=new ClassA[10]。触发了一个名为[LClassA的类的初始化,它是一个由虚拟机自动生成的、直接继承于Object的类,创建动作由字节码指令newarray触发。
  3. 常量会在编译阶段存入调用类的常量池。

编译器会为接口生成<clinit>()构造器,用于初始化接口中定义的成员变量。一个接口在初始化时,并不要求其父类接口全部完成了初始化,只有在真正使用到父接口的时候才会初始化。

1.      加载

  1. 通过一个类的全限定名来获取此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在java堆中生成一个代表这个类的Class对象,作为方法区这些数据的访问入口。

2.      验证

验证:确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

虚拟机规范:如果验证到输入的字节流不符合Class文件的存储格式,就抛出一个java.lang.VerifyError异常或其子类异常。

  1. 文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。这个阶段的验证时给予字节流进行的,经过了这个阶段的验证之后,字节流才会进入内存的方法区中进行存储所以后面的验证阶段都是给予方法区的存储结构进行的。
  2. 元数据验证:对类的元数据信息进行语义校验,保证不存在不符合java语言规范的元数据信息。
  3. 字节码验证:进行数据流和控制流分析,对类的方法体进行校验分析,保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为。
  4. 符号引用验证:发生在虚拟机将符号引用转化为直接引用的时候(解析阶段),对常量池中的各种符号引用的信息进行匹配性的校验。

3.      准备

准备阶段是正式为类变量分配内存并设置类变量初始值(各数据类型的零值)的阶段,这些内存将在方法区中进行分配。但是如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量值就会初始化为ConstantValue属性指定的值。

public static final int value=122;

4.      解析

解析阶段是在虚拟机将常量池内的符号引用替换为直接引用的过程。

符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。

直接引用:直接引用可以是直接指向目标的指针、相对偏移量或者一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。

 

  A.    类或接口(对应于常量池的CONSTANT_Class_info类型)的解析:

假设当前代码所处的类为D,需要将一个从未解析过的符号引用N解析为一个类或接口C的直接引用:

  1. 如果C不是一个数组类型,虚拟机将会把代表C的全限定名传递给D的类加载器去加载这个类。
  2. 如果C是一个数组类型,并且数组的元素类型为对象(N的描述符类似[Ljava.lang.Integer),将会加载数组元素类型(java.lang.Integer),接着由虚拟机生成一个代表此数组维度和元素的数组对象。
  3. 如果以上过程没有发生异常,则C在虚拟机中已经成为了一个有效的类和接口了,之后还要进行的是符号引用验证,确认D是否具有对C的访问权限,如果没有,将抛出java.lang.IllegalAccessError异常。

  B.     字段(对应于常量池的CONSTANT_Fieldref_info类型)解析:

  1. 对字段表中的class_index项中索引的CONSTANT_Class_info符号引用进行解析。用C表示这个字段所属的类或接口。
  2. 如果C本身就包含了简单名称和字段描述符都与目标相匹配的字段,则返回这个字段的直接引用。
  3. 否则,如果C实现了接口,则会按照继承关系从下往上递归搜索各个接口和他的父接口,如果接口中包含了简单名称和字段描述符都与目标相匹配的字段,则返回这个字段的直接引用。
  4. 否则,如果C不是java.lang.Object类型的话,将会按照继承关系从下往上递归的搜索其父类,如果在父类中包含了简单名称和字段描述符都与目标相匹配的字段,则返回这个字段的直接引用。
  5. 否则,查找失败,抛出java.lang.NoSuchFieldError异常。

虚拟机的编译器实现可能会更严格:如果一个同名字段同时出现在C实现的接口和父类中,或者同时在自己或父类的多个接口中出现,编译器将可能拒绝编译。

C.     类方法(对应于常量池的CONSTANT_Methodref_info类型)解析:

  1. 对方法表中的class_index项中索引的CONSTANT_Class_info符号引用进行解析。用C表示这个方法所属的类或接口。
  2. 类方法和接口方法符号引用的常量类型定义是分开的,如果在类方法表中发现class_index中索引的C是个接口,则抛出java.lang.IncompatibleClassChangeError。
  3. 在类C中查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用。
  4. 否则,在C的父类中递归查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用。
  5. 否则,在C实现的接口列表及它们的父接口中递归的查找是否有简单名称和描述符都与目标相匹配的方法,如果有说明C是个抽象类,查找结束,抛出java.lang.AbstractMethodError异常。
  6. 否则,查找失败,抛出java.lang.NoSuchMethodError异常。
  7. 如果查找返回了直接引用,将会对这个方法进行权限验证,如果发现不具备对这个方法的访问权限,则抛出java.lang.IllegalAccessError异常。

  D.    接口方法(对应于常量池的CONSTANT_InterfaceMethodref_info类型):

  1. 对方法表中的class_index项中索引的CONSTANT_Class_info符号引用进行解析。用C表示这个方法所属的类或接口。
  2. 如果在接口方法表中发现class_index中索引的C是个类,则抛出java.lang.IncompatibleClassChangeError。
  3. 否则,在接口C中查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用。
  4. 否则,在接口C的父接口中递归查找,知道java.lang.Object类(包括在内),看是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用。
  5. 否则,查找失败,抛出java.lang.NoSuchMethodError。

5.      初始化

初始化阶段是执行类构造器<clinit>()方法的过程。

  1. <clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的。静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但是不能访问。

2. 方法与实例构造器<init>()不同,不需要显示的调用父类构造器,虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()已经执行完毕。

3. <clinit>()方法对于类或接口来说不是必须的,如果一个类中没有静态语句块也没有对变量的赋值操作,那么编译器可以不为这个类生成<clinit>()方法。

4. 执行接口的<clinit>()不需要先执行父接口的<clinit>()方法,只有当父接口中定义的变量被使用时,父接口才会被初始化。接口的实现类在初始化时也不会执行接口的<clinit>()方法

5. 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁和同步,如果多个线程同时去初始化一个类,则只会有一个线程去执行这个类的<clinit>()方法,其他线程需要阻塞等待

转载于:https://www.cnblogs.com/moonandstar08/p/4876035.html

相关文章:

dw8与mysql的连接,VS2019连接mysql8.0数据库的教程图文详解

1.首先准备好vs2019以及mysql数据库&#xff0c;两者都可以去官网下载&#xff0c;我们直接描述连接过程。2.连接&#xff1a;第一步&#xff1a;打开mysql的安装目录&#xff0c;我本地的安装目录如下&#xff1a;(注意是否有include和lib文件夹)第二步&#xff1a;打开vs2019…

IOS中打开应用实现检查更新的功能

//检查更新页面- (void)Renew{ NSDictionary *infoDic [[NSBundle mainBundle]infoDictionary]; NSString *version [infoDic valueForKey:"CFBundleShortVersionString"]; NSString *ipstr [NSObject deviceIPAdress]; NSString *p…

CSS3边框背景-边框背景(-border-image)

另一个令人兴奋的新特征是边框图片。有了这项功能您可以定义一个图像被用来代替正常的边框的一个组成部分。这项功能实际上是分成了几个属性&#xff1a;边框和边框角的形象。这两个值是&#xff1a; border-image: border-top-imageborder-right-imageborder-bottom-imagebord…

Promise的实例用法

设定函数 function chiFan() {return new Promise(function(resolve, reject) {console.log("chiFan");}) }function shuiJiao() {return new Promise(function(resolve, reject) {console.log("shuiJiao");}) }function daDouDou() {return new Promise(f…

php文件夹列表,php获取文件夹下面的文件列表和文件夹列表

function getDir($dir) {$dirArray[] NULL;if (false ! ($handle opendir( $dir ))) {$i0;while ( false ! ($file readdir( $handle )) ) {//去掉"“.”、“..”以及带“.xxx”后缀的文件if ($file ! "." && $file ! ".."&&!strp…

SharePoint API测试系列——Records.BypassLocks测试

转载请注明出自天外归云的博客园&#xff1a;http://www.cnblogs.com/LanTianYou/ 对于SharePoint中已经是Record的Item&#xff0c;我们想要修改他的属性&#xff0c;这在UI界面是无法完成的&#xff1a; 这时需要通过Records.BypassLocks API来完成。设计一个tool&#xff0c…

我对自动化测试工程师招聘的建议

给以前公司招聘人员做的一个培训:/Files/killmyday/2011年PTA测试培训课件.zip 转载于:https://www.cnblogs.com/killmyday/archive/2012/04/15/2450108.html

解决请求中400的问题

具体报错&#xff1a;2019-03-19 12:01:35,097 - request - DEBUG - json_data: {timestamp: 1552968086846, status: 400, error: Bad Request, exception: org.springframework.http.converter.HttpMessageNotReadableException, message: "JSON parse error: Unrecogni…

java 中lock,java中lock获取锁的四种方法

在java接口中会存放着许多方法&#xff0c;方便线程使用时的直接调用。对于lock接口大家都不陌生&#xff0c;我们已经初步对概念进行了理解。那么在获取锁的方法上想必还不是很清楚。下面我们就lock获取锁的四种方法分别进行概念的介绍&#xff0c;然后就其中的tryLock()方法带…

RadASM的测试工程!

RadASM已经安装完毕了&#xff0c;是否可以正常工作了呢&#xff1f;我们通过创建一个工程来测试一下&#xff0c;下面就是创建这个测试工程的过程&#xff1a; 1&#xff0c; 2&#xff0c; 3&#xff0c; 4&#xff0c; 5&#xff0c; 6&#xff0c; 7&#xff0c; 8&#xf…

单片机 键盘

键盘分类&#xff1a; &#xff08;1&#xff09;编码键盘 键盘上闭合键的识别由专门的硬件编码器实现&#xff0c;并产生键编码号或键值的称为编码键盘&#xff0c;如计算 机键盘。 &#xff08;2&#xff09;非编码键盘 靠软件编程来识别的键盘称为非…

React typescript issue

多个输入框发生变化时&#xff0c;setState: this.setState({[e.target.name]: e.target.value} as componentState) 转载于:https://www.cnblogs.com/Nyan-Workflow-FC/p/10561058.html

java 匿名list,java创造匿名对象的两种方法

在java中有时候需要一些匿名对象的使用。可能有些小伙伴拿还不会创造&#xff0c;其实我们在学习一些方法时都或多或少的接触过。本篇所要讲到的创造匿名对象总结了两种方法&#xff0c;分别是静态工具方法和Lambda表达式&#xff0c;我们会在下文中为大家进行分析和实例代码展…

apk签名验证机制

声明&#xff1a; 1.本帖转载自&#xff1a;http://riusksk.blogbus.com/logs/272154406.html&#xff0c;仅供自用&#xff0c;勿喷 2.欢迎交流学习 签名后的APK&#xff0c;在/META-INF目录下会生成以下3个文件&#xff1a; MANIFEST.MF&#xff1a;保存除META-INF文件以外其…

spring cloud微服务分布式云架构--hystrix的使用

hystrix主要作用在服务消费者&#xff0c;进行应用的保护&#xff0c;当请求的服务请求超时时&#xff0c;做出相应的处理&#xff0c;避免客户端一直进行请求等待&#xff0c;避免在高并发的情况出现服务器死机&#xff08;请求过多&#xff0c;内存不足&#xff09; 接下来的…

JSP项目目录中每个文件夹及配置文件的作用

/WEB-INF目录&#xff1a;Web应用应用部署目录&#xff0c;浏览客户是看不到该目录下的文件的&#xff0c;该目录下的文件专供Web服务器专用。web.xml&#xff1a;部署描述文件&#xff0c;/WEB-INF目录下最重要的文件&#xff0c;它描述了程序的部署、配置信息&#xff0c;为W…

java里锛是什么意思,java实验总结

p3person.newperson("jane", 13, f);System.out.println(p1);System.out.println(p2);System.out.println(p3);}}1. 设计一个数据单元类DataUnit, 它包含学号(Number)和姓名(Name)两个数据成员。2. 设计两个线程&#xff0c;一个线程往数据单元里写信息&#xff0c;一…

c调用python

tables.py global gtablesgtables { 1001:"张鲁p", 1002:"凌p", 2001:"李进a", 2002:"vb" } from tables import gtables def get_cmd(key, value): name "0"; try: name gtables[key] …

梦美生命获1亿元A轮融资,鼎晖领投

3月20日消息&#xff0c;跨境辅助生殖医疗IVF服务的企业梦美生命&#xff08;下称&#xff1a;梦美&#xff09;已获得约1亿人民币A轮融资&#xff0c;由鼎晖领投&#xff0c;淡蓝及天使投资方开牛投资跟投&#xff0c;本轮融资主要用于人才引进以及市场推广。 梦美成立于2013…

网站锁定php文件命令,PHP文件锁定读写的一点注意_php

都说文本方式容易出现文件锁定失效等乱七八糟的问题.其实并不是失效, 而是写法有些不对.被 lock_ex 后的文件 再以read模式 fopen 的话将读到空内容!!!如果没有判断就把它作操作后再写入就出错啦....很多问题出在这里.再来补充一下如果一个文件被以write的模式fopen后并 flock(…

luogu P1280 尼克的任务 序列DP

我们发现&#xff0c;我们从前往后DP有苦难&#xff0c;因为现在的选择存在后效性。 如果我们从后向前DP&#xff0c;f[i]表示从i时刻到下班的最小工作时间&#xff0c;从后向前转移&#xff0c;则不存在后效性问题。 1 #include <cstdio>2 #include <vector>3 usi…

第一次使用cookie

给招行做的一个小游戏&#xff0c;有个需求是&#xff1a;分数第一次达到500会弹出一个提示框。之前没有使用过cookie&#xff0c;在网上搜了些资料&#xff0c;最终还是顺利实现了功能。在这里贴一下代码。 <%! //初始化cookiepublic String getCookie(HttpServletRequest …

保证你现在和未来不失业的10种关键技【转载】

在当今的IT就业市场&#xff0c;有人欢喜有人忧。有人对目前的工作和薪水很满意&#xff0c;有人目前正面临着下岗&#xff0c;或者已经下岗…… 可能你是公司里唯一谙熟某项关键技术的高手&#xff0c;缺了你&#xff0c;公司便玩不转了&#xff1b;也可能你所在的公司对你现…

MySQL建表枚举分区SQL,【mysql备份】02、Xtrabackup备份mysql

一、Xtrabackup概述1、Xtrabackup简介Xtrabackup是由percona提供的mysql数据库备份工具&#xff0c;据官方介绍&#xff0c;这也是世界上惟一一款开源的能够对innodb和xtradb数据库进行热备的工具。官网&#xff1a;https://www.percona.com/InnoDB存储引擎支持热备&#xff0c…

CentOS目录结构超详细版

最近初学Linux 对linux的目录产生了很多疑问&#xff0c;看到这篇文章&#xff0c;让我顿时对目录有了一个清晰的认识&#xff01;推荐给大家&#xff01; ----------------------------------------------------------------------------------------------------------------…

02_计算机科学和软件工程的区别

计算机科学和软件工程同属计算机类专业&#xff0c;他们的联系确实非常紧密&#xff0c;但还是有很多区别的。 计算机科学&#xff1a; 偏重于硬件与计算机理论方面的学习研究&#xff0c;像计算机原理&#xff0c;计算机系统结构等方面的内容。当然也会涉及软件方面&#xff0…

来自 Google 的 R 语言编码风格指南

来自 Google 的 R 语言编码风格指南 R 语言是一门主要用于统计计算和绘图的高级编程语言. 这份 R 语言编码风格指南旨在让我们的 R 代码更容易阅读、分享和检查. 以下规则系与 Google 的 R 用户群体协同设计而成. 概要: R编码风格约定文件命名: 以 .R (大写) 结尾标识符命名: v…

php中去空函数trim,PHP中trim()函数简单使用指南

string trim ( string $str [, string $charlist ] ) - 去除字符串首尾处的空白字符(或者其他字符)trim()函数当第二个参数为空时&#xff0c;默认去掉空格、制表符、换行符、回车符、垂直制表符等&#xff0c;当加入第二个参数时复制代码 代码如下:1) trim( \"string\&…

03 基本数据类型、运算符 输入输出

代码注释 单行注释&#xff1a;# 多行注释&#xff1a;可以用三对双引号""" """ 基本数据类型 事物的状态有不同的种类&#xff0c;使用不同类型的值去记录不同的状态 一、数字类型 1.整型int 定义&#xff1a;age10 #ageint(10)作用&#xff1…

wordpress调用树形目录

wordpress调用树形结构目录最简单的方法就是使用方法就是使用函数&#xff1a;<?php wp_list_categories( $args ); ?>另一种方法&#xff0c;方便自定义样式,代码如下&#xff1a;<div class"rightbox"><div class" cat_right_bg cat_title&…