JVM(四)类加载机制
1.静态绑定和动态绑定
静态绑定:即前期绑定,在程序执行前方法已经被绑定,此时由编译器或者其他连接程序实现,针对Java,可以理解为编译期的绑定,java中只有final、static、private和构造方法是前期绑定的。
动态绑定:即晚期绑定,也叫运行时绑定,在运行时根据具体的类型进行绑定,在java中几乎所有的方法都是后期绑定。
2.加载阶段:
①要做的三件事: a.通过一个类的全限定名来获取定义的二进制流文件(class文件、jar包、网络中、其他应用jsp)
b.将这个字节流的静态的存储结构转化为方法区的运行时
c.在java堆中生成一个代表这个类的java.lang.class对象,作为对方法区这些数据的访问入口。
②相对于类加载其他阶段而言,是可控性最强的, 可以使用系统提供的也可以定义自己的类加载器加载。
③加载阶段完成后,虚拟机外部的二进制字节流就会按照虚拟机需要的格式存储在方法区中,而且在java堆中也创建了一java.lang.class对象来访问方法区的数据。
3.类加载器:
① 对于任何一个类来说,都需要由它的类加载和这个类本身去确定其在虚拟机的唯一性,也就是说两个类来源于同一个Class文件,只要加载他们的类加载器不同,那这两个类就必定不相等。 这里的相等时包括。equals()、isAssingableFrom()、isInstance()等方法的返回结果,也包括instanceof的判定结果
② 站在虚拟机的角度,只存在两种类加载器
启动类加载器 ---- 虚拟机自身的一部分
所有其他的类加载器 ---- 独立于虚拟机之外,在启动类加载器加载到内存之后去加载的。
③ 站在开发人员的角度,大致可发三类
启动类加载器 JDK\jre\lib
扩展类加载器 负责加载JDK\jre\lib\ext中或者由java.ext.dirs系统变量指定的路径的所有类库(javax开头的)
应用程序类加载器 加载用户类路径下面的类,如果程序中没有定义过自己的类加载器,这个就是默认使用的。
④自己定义类加载 的好处
JVM自带的ClassLoader只懂得从本地文件系统加载标准的Class文件,
a.在执行非置信代码之前,自动验证数字签名
b.动态的创建符合用户特定需要的定制化构建类
c.从特定的场所取得class ,例如数据库和网络中。
⑤双亲委派模型是
工作流程是
如果一个类加载器收到了类加载的请求,它首先不会自己加载这个类,而是把请求委托给父类去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的类加载器中, 只有当前父加载器在它的搜索范围内没有找到所需的类时,即无法完成该加载,子类加载器才回去尝试。
优点
java类随着它的类加载一起具备了具有一种带有优先级的层次关系。
java.lang.Object在JDK\jre\lib的rt.jar中,因此无论哪一个类加载器要加载类,都保证会由启动类加载器加载,也保证了Object类在程序中各种类加载器都是同一个类
4.验证:
为了确保Class文件中的二进制流信息格式符合当前虚拟机的要求,而且不会危害虚拟机自身的安全。主要有四个验证:文件格式验证,元数据格式验证,字节码验证,符号引用验证。
文件格式验证:验证字节流是否符合Class文件的规范,并且能被当前版本的虚拟机处理,该验证的目的是为了保证输入的字节流能够正确被解析存储到方法区里面。后面的 三个验证都是基于方法区结构的验证。
元数据验证:对类的元数据信息进行语义验证,(对类中各数据类型进行语法校验)
字节码验证:该阶段验证的主要工作是验证数据流和控制流,对类的方法体进行校验分析,保证类的方法在执行的时候不会对JVM做出危害行为。
符号引用验证:发生在将符号引用转化为直接引用的时候,对类自身以外的信息(常量池的各种符号引用)进行匹配性的验证。
5.准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配,有几点需要注意:
①这时候进行内存分配的仅包括类变量,实例变量在对象实例化时在堆中分配。
②这里设置是初始值,不是在类中被显示赋予的值。
a.基本数据类型:对于类变量和全局变量,如果不显式的赋值使用,系统会赋予默认值,对于局部变量必须赋值,否则编译不通过。
b.同时被static和final修饰的值, 必须在声明的时候显式的赋值,否则编译不通过,
c.被final修饰,成员变量:在类中声明或者在构造函数初始化的时候赋值,一旦赋值,不能更改
局部变量:在使用前赋值
(在类中声明或者在初始化的时候赋值,在使用前必须进行赋值,系统不会赋予默认的值)。
d.对于引用类型,数组引用和对象引用,没赋值,则系统赋null
e.数组元素没有被赋值,根据数组元素类型系统赋默认的值。
③如果是static和final修饰的,在准备阶段就会初始化指定的值。
在编译期放到了调用它的类常量池里面
6.解析
符号引用到直接引用的过程,可能开始于初始化之前和之后。JVM自己决定。主要针对:类或接口的解析、字段解析、类方法解析、接口方法解析。
①类或接口的解析:判断所要转化的是数组类型的,还是普通对象类型的,从而进行不同的解析。
②字段解析:会首先在本类中查找是否包含有简单名称和字段描述符都与目标相匹配的字段,如果有,查找结束,如果没有,则会按照继承关系,从上往下递归搜索该类所实现的各个接口和他们的父接口。 还没有的话,搜从上往下递归搜索其父类,直至查找结束。
③类方法解析:和字段解析相差不多,只是多了判断该方法所处是类还是接口的步骤,先搜索父类,在搜索接口。
④接口方法解析:递归查找父接口。
7.初始化
初始化阶段是执行类构造器<clinit>方法的过程,按照程序员的主观计划去初始化类变量和其他资源。
①编译器自动收集类中的所有类变量的赋值动作和静态语句块合并产生的,编译器收集的顺序是源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,之后的变量,可以再静态代码块赋值,但是不能访问。
②<clinit>方法与实例构造器<init>方法不同,它不需要显式的调用父类构造器,虚拟机会保证子类的<clinit>的执行前,父类的<clinit>已经执行完成, 因此在虚拟机中第一个被执行的肯定是Object的<clinit>
③<clinit>对于类或接口来说不是必须的,如果一个类中没有静态语句块,也没有对类变量进行赋值操作,那么编译器可以不为这个类生成<clinit>方法
④接口中不能使用静态语句块,但仍然有类变量初始化的赋值操作,因此会生成<clinit>方法,但是与类不一样的是:不需要先执行父类的<clinit>,只有在使用父类定义的类变量时,才会触发, 另外,在接口的实现类在初始化时,不会执行接口的<clinit>方法
⑤虚拟机会保证一个类的<clinit>方法在多线程中是同步的和加锁的,如果多个线程同时去初始化一个类,那么只有一线程去执行,其他线程都需要阻塞等待。(屏障点线程)
总结
整个类加载过程,只有在类加载阶段,用户程序可以自动以类加载器参与,其余所有动作都由虚拟机主导完后,到了初始化才开始执行,也只限于<clinit>方法。主要是将class文件加载到虚拟机中,真正执行的操作,是在加载完成后才进行的。
JVM(四)类加载机制的更多相关文章
- JVM内存结构 JVM的类加载机制
JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...
- JVM的类加载机制全面解析
什么是类加载机制 JVM把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制. 如果你对Class文件的结 ...
- 一文教你读懂JVM的类加载机制
Java运行程序又被称为WORA(Write Once Run Anywhere,在任何地方运行只需写入一次),意味着我们程序员小哥哥可以在任何一个系统上开发Java程序,但是却可以在所有系统上畅通运 ...
- JVM之类加载机制
JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...
- 大白话谈JVM的类加载机制
前言 我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢. 如果懂得了JVM的运行原理和内存模型,像是一些JVM调优.垃圾回收机制等等的问题我们才 ...
- 【JVM】类加载机制
原文:[深入Java虚拟机]之四:类加载机制 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 类加 ...
- 深入理解JVM(3)——类加载机制
1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...
- 漫谈JVM之类加载机制(篇一)
前言 最近在看一本书,发现代码里用到了Thread.currentThread().getContextClassLoader(),为什么类加载器还与线程有关系呢,为什么不直接使用ClassLoade ...
- JVM的类加载机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类加载的过程: 包括加载.链接(含验证.准备 ...
随机推荐
- CodeForces 804C Ice cream coloring
Ice cream coloring 题解: 这个题目中最关键的一句话是, 把任意一种类型的冰激凌所在的所有节点拿下来之后,这些节点是一个连通图(树). 所以就不会存在多个set+起来之后是一个新的完 ...
- CodeForces Round #514 (div2)
A:Cashier 题意:问可以休息多少次. 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen( ...
- 前后端分离,获取token,验证登陆是否失效
maven依赖 <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</a ...
- 解决rac错误 ORA-01102: cannot mount database in EXCLUSIVE mode
启动 Oracle 11g RAC数据库时出现以下错误.只能启动其中一个节点(rac01),另一个节点启动不了(rac02).可能是以前修改cluster_database这个参数引起的.在Orac ...
- SpringBoot初体验之整合SpringMVC
作为开发人员,大家都知道,SpringBoot是基于Spring4.0设计的,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程.另外Spr ...
- Web框架之Gin
Gin是一个用Go语言编写的web框架.它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍. 如果你是性能和高效的追求者, 你会爱上Gin. ...
- Django-开放静态资源-获取请求携带的数据-pychram连接数据库-修改Django默认数据库-DjangoORM操作--表管理-记录管理-01
目录 关于静态资源访问 为什么要配置静态文件才能获取静态资源 常见的静态文件种类 如何配置来开启访问权限 禁用浏览器缓存 django的自动重启机制(热启动) 静态文件接口动态解析 向服务器发送数据 ...
- 手写RPC框架指北另送贴心注释代码一套
Angular8正式发布了,Java13再过几个月也要发布了,技术迭代这么快,框架的复杂度越来越大,但是原理是基本不变的.所以沉下心看清代码本质很重要,这次给大家带来的是手写RPC框架. 完整代码以及 ...
- FreeSql (三)实体特性
主键(Primary Key) class Topic { [Column(IsPrimary = true)] public int Id { get; set; } } 约定: 当没有指明主键时, ...
- Java连载31-递归方法练习、面向对象
一.实现阶乘(一种用递归,一种普通方法) public static void main(String[] args) { System.out.println(factorial(5)); Syst ...