java类加载及类初始化
1.前言
java是跨平台语言,主要是因为它的java虚拟机的存在,java有事编译语言,所以需要将编写的java文件编译成jvm可运用的class字节码文件。在java中一切皆对象。对于Java虚拟机而言,一个Java类也是一个对象。一个类在JVM中被实例化成一个对象,需要经历三个过程:加载、链接和初始化。
2.加载
通过读取字节码二进制.class文件将类加载到内存,从而达到类的从硬盘上到内存上的一个迁移,所有的class必须加载到内存才能工作。一个Java类在被加载到内存后会在Java堆中创建一个类(java.lang.Class)对象,同时JVM为每个类对象都维护一个常量池(类似于符号表)并将这个字节流代表的静态存储结构转换为方法区的运行时数据结构。
- Bootstrap ClassLoader:这个加载器不是一个Java类,而是由底层的c++实现,负责在虚拟机启动时加载Jdk核心类库以及加载后两个类加载器。
- Extension ClassLoader:是一个普通的Java类,继承自ClassLoader类,负责加载{JAVA_HOME}/jre/lib/ext/目录下的所有jar包。
- App ClassLoader:是Extension ClassLoader的子对象,负责加载应用程序classpath目录下的所有jar和class文件。
- 自定义类加载器
3.链接
(1)验证
验证是类加载的第二个阶段,这个阶段也是持续时间最长(从阶段连续性来说),这个阶段从加载开始进行,一直进行到解析阶段结束。验证是为了保证class文件中的内容是符合虚拟机规范的二进制字节流,防止通过执行一些不安全的二进制字节流而导致虚拟机奔溃。 从整体来看,类加载过程的验证阶段可以分为四个部分:文件格式验证、元数据验证、字节码验证和符号引用验证。
(2)准备
准备阶段是证实为类变量分配内存并且设置初始化值的阶段,这些变量所使用的内存都在方法区分配。这个阶段进行初始化的数据只有静态字段,并且是赋值初始化值(final修饰的字段除外),不是代码中定义的值。
public static int value = 123;在准备阶段,value在方法区分配内存,并且设置初始值0,如果value被final修饰,形如:public static final int value = 123;则该变量在准备阶段将会被赋值123,并且不会引起类的初始化过程,示例及说明见第二部分(类加载的时机)的示例。
(3)解析
解析阶段是虚拟机将符号引用转化为直接引用的过程,符号引用在之前已经介绍过了,在class文件中以形如"CONSTANT_Class_info"、"CONSTANT_Fieldref_info"、"CONSTANT_Methodref_info"格式存在。符号引用是指在class文件内部的引用指向,也就是说,在class文件内部,会对各个方法,变量进行编号,当存在方法之间的调用或变量之间的引用时,以此编号为引用,找到调用的方法和变量。直接应用就是在对方法和变量解析之后将方法和变量的地址值返回到调用方,以便在调用的时候快速直接的定位方法和变量。由于在class文件没有加入到jvm时,我们是不知道方法的具体分配位置的,所以以符号引用表示,到class加载之后,在这个运行环境中,我们是可以定位方法和变量的地址的。所以在此时做解析。
4.初始化
初始化阶段是类加载过程的最后一步,这个阶段才开始真正的执行用户定义的Java程序。在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则需要为类变量(非final修饰的类变量)和其他变量赋值,其实就是执行类的<clinit>()方法。在Java语言体系中,<clinit>()是由编译器生成的,编译器在编译阶段会自动收集类中的所有类变量的赋值动作和静态语句块(static{})中的语句合并而成的,编译器收集的顺序是由语句的顺序决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在静态语句块之后的变量,可以赋值,但是不能访问。
<clinit>()方法与类的构造方法不同,它不需要用户显示的调用,虚拟机会保证父类的<clinit>()方法先于子类的<clinit>()执行,java.lang.Object的<clinit>()方法是最先执行的。接口中不能使用用静态语句块,所以接口的<clinit>()只包含类变量,所以接口的<clinit>()方法执行时,不要求限制性父接口的<clinit>()方法。<clinit>()方法对于类和接口来说不是必须的,如果类或接口中没有定义类变量,也没有静态语句块,那么编译器将不为这个类或者接口生成<clinit>()方法,如果类或者接口中生成了<clinit>()方法,那么这个方法在执行过程中,虚拟机会保证在多线程环境下的线程安全问题。
虚拟机规范给了严格规定,有且只有以下几种情况必须立即对类进行初始化:
1、遇到new、putstatic、getstatic及invokestatic这4条字节码指令时,如果类没有初始化,则立即进行初始化,这4个命令分别代表实例化一个类、设置&读取一个静态字段(没有被final修饰)、调用类的静态方法;
2、使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有初始化;
3、当初始化一个类的时候,发现其父类没有初始化;
4、当虚拟机启动时,需用将执行启动的主类(有main()方法的那个类)进行初始化;
5、当使用动态语言时,如果一个java.lang.invoke.MethodHandle实例最终的解析结果是REF_getStatic、REF_putStatic、REF_invokeStatic句柄时,并且这个句柄对应的类没有初始化。
感谢:https://blog.csdn.net/u010942465/article/details/81709246
java类加载及类初始化的更多相关文章
- 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
- Java类加载和类反射回顾
今天学习Spring,突然想重新复习一下Java类加载和类反射的.巩固一下底层原理.部分参考了李刚老师的<疯狂Java讲义>和陈雄华.林开雄的<Spring3.x企业应用开发实战&g ...
- java类加载和对象初始化
对象初始化过程: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 3.其次,初 ...
- JAVA基础2——类初始化相关执行顺序
类初始化相关执行顺序 几个概念说明 代码块的含义与作用 static静态代码块: 一般用于初始化类中的静态变量.比如:给静态的数组或者list变量赋初值.使用static静态代码块进行初始化与直接在定 ...
- java中的类加载器ClassLoader和类初始化
每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一 ...
- Java程序设计19——类的加载和反射-Part-A
1 本文概要 本章介绍Java类的加载.连接和初始化的深入知识,并重点介绍Java反射相关的内容.本章知识偏底层点,这些运行原理有助于我们更好的把我java程序的运行.而且Java类加载器除了根加载器 ...
- 一文读懂Java类加载机制
Java 类加载机制 Java 类加载机制详解. @pdai Java 类加载机制 类的生命周期 类的加载:查找并加载类的二进制数据 连接 验证:确保被加载的类的正确性 准备:为类的静态变量分配内存, ...
- ClassLoader类加载器 & Java类加载机制 & 破坏双亲委托机制
ClassLoader类加载器 Java 中的类加载器大致可以分成两类: 一类是系统提供的: 引导类加载器(Bootstrap classloader):它用来加载 Java 的核心库(如rt.jar ...
- jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解
一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机: 1 ...
随机推荐
- Docker中运行EOS FOR MAC
基本要求以及依赖 安装 docker for mac ➡️ https://www.docker.com/products/docker-desktop docker需要7GB+内存.电脑右上角doc ...
- 死磕 java集合之TreeMap源码分析(二)- 内含红黑树分析全过程
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 插入元素 插入元素,如果元素在树中存在,则替换value:如果元素不存在,则插入到对应的位置, ...
- vue组件,可以通过npm引用的组件
本文章通过实现一个vue-dialog的弹出层组件,然后附加说明如果发布此包到npm,且能被其他项目使用. 功能说明 多层弹出时,只有一个背景层. 弹出层嵌入内部组件. 弹出层按钮支持回调 源码下载 ...
- 8分钟学会使用AutoMapper
一.什么是AutoMapper与为什么用它. 它是一种对象与对象之间的映射器,让AutoMapper有意思的就是在于它提供了一些将类型A映射到类型B这种无聊的实例,只要B遵循AutoMapper已经建 ...
- log4cplus使用(三)-日志重定向
本文讲述的是log4cplus日志输出到qt widget,封装了serverSocket. log4cplus支持用户自定义输出设备,只需要继承自Appender,或者Appender子类, ...
- 免费SSL证书(支持1.0、1.1、1.2)
由于公司要开发微信小程序,而微信小程序的接口需要https协议的,并且要支持TLS1.0.TLS1.1.TLS1.2.如果仅仅是为了开发小程序,安全等级又不用太高,可以选择免费的SSL证书 在这里选择 ...
- .net文件上传默认限制了大小4M
如果需要上传比较大的文件(文件大小大于4M).则需要在webconfig里面<system.web>修改httpRuntime节点: <httpRuntime targetFrame ...
- SignalR学习笔记(三)Self-Host
SignalR可以借助Owin摆脱对IIS的依赖,实现Self-Host,使得SignalR有了部署在非Windows平台的可能. 什么是Owin Owin的英文全称是Open Web Interfa ...
- 小技巧,把Markdown文本发布到微信公众号文章
估计很多人都是这样,平常工作在github,等到有成果要发布,又要写微信公众号. github用Markdown,微信公众号,至少截止今天,还是沿用富文本的方式.不是说富文本不好,但每次精心撰写的内容 ...
- Solr 08 - 在Solr Web管理页面中查询索引数据 (Solr中各类查询参数的使用方法)
目录 1 Solr管理页面的查询入口 2 Solr查询输入框简介 3 Solr管理页面的查询方案 1 Solr管理页面的查询入口 选中需要查询的SolrCore, 然后在菜单栏选择[Query]: 2 ...