Jvm之class文件的加载、初始化
编写的java文件在要真正运行时,会首先被编译成 “.class"结尾的二进制文件,然后被虚拟机加载。那么在虚拟机中一个class文件要成为java实例,需要经历好几个步骤:
一、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")XM申请代理http://www.kaifx.cn/broker/xm.html,进行类装载时,会自动执行类中的静态代码块,但不会执行构造方法
使用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、当一个接口初始化的时候,并不要求其父接口也被初始化,只有真正使用到父接口的时候才会初始化。
四、case class与class的区别
1、初始化的时候,不需要new,当然你也可以加上,普通类一定需要加上new
class ABC(name:String){
def ff(): Unit ={
}
}
case class ABC1(name:String){
def ff1(): Unit ={
}
}
val abc1=ABC1("fg")
val abc= new ABC("xx")
2、toString的实现更加漂亮
println(abc1.toString)
println(abc.toString)
3、默认实现了equals hashcode
4、默认是可以序列化的,也就是实现了Serializable
5、自动从scala.Producet中继承了一些函数
6、case class构造函数的参数是publiec级别的,我们可以直接访问
7、支持模式匹配
Jvm之class文件的加载、初始化的更多相关文章
- Java_类文件及加载机制
类文件及类加载机制 标签(空格分隔): Java 本篇博客的重点是分析JVM是如何进行类的加载的,但同时我们会捎带着说一下Class类文件结构,以便对类加载机制有更深的理解. 类文件结构 平台无关性 ...
- jvm学习:类的加载、连接、初始化、常量
类在jvm中有这几个过程类的加载.连接.初始化.使用.卸载 类的加载 类的加载是将class文件中的二进制数据加载到内存中,将其放在运行时的数据区:方法区内,然后在内存中创建一个 java.lang. ...
- 字节码(.class)文件的加载过程
类加载 在Java代码中,类型的加载.连接与初始化过程都是在程序运行期间完成的. 类型可以是Class,Interface, 枚举等. Java虚拟机与程序的生命周期 在如下几种情况下,Java虚拟机 ...
- JVM之类加载器、加载过程及双亲委派机制
JVM 的生命周期 虚拟机的启动 Java 虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实 ...
- Java虚拟机JVM学习02 类的加载概述
Java虚拟机JVM学习02 类的加载概述 类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对 ...
- HTML页面处理以及资源文件的加载
Javascript 异步加载详解 这篇文章很详细的介绍了HTML的页面处理以及资源文件的加载. 本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading ...
- Spring之IOC容器加载初始化的方式
引言 我们知道IOC容器时Spring的核心,可是如果我们要依赖IOC容器对我们的Bean进行管理,那么我们就需要告诉IOC容易他需要管理哪些Bean而且这些Bean有什么要求,这些工作就是通过通过配 ...
- Web前端性能优化——如何有效提升静态文件的加载速度
WeTest 导读 此文总结了笔者在Web静态资源方面的一些优化经验. 一.如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标.那么为了提高页 ...
- ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)
加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: ...
随机推荐
- Comet OJ - contest #3 C DP
题意:给你一个长度为n序列,和一个数m,问这个序列有多少个子序列,满足这个子序列的所有子序列的和是m的倍数?答案对1e9 + 7取模,n, m范围到5e3; 思路:容易发现,如果一个子序列的长度是n, ...
- 初撩Django-RESTful-rest_framework视图函数
rest_framework中的视图函数: View函数 APIView函数 APIView的子类 mixins函数 viewsets函数 1.View函数 2.APIView函数 3.APIView ...
- Java 基础 -- BigInteger BigDecimai大数
BigInteger 加减乘除 BigInteger bi1 = new BigInteger("123456789") ; // 声明BigInteger对象 BigIntege ...
- c++ 兰姆达表达式
#include<iostream> using namespace std; int main() { int a = 1; int b = 2; aut ...
- [Android开发] 代码code设置9.png/9-patch 图片背景后,此view中的TextView等控件显示不正常(常见于listview中)
== 0) { convertView.setBackgroundResource(R.drawable.list_gray_9); } else { convertView.setBackgroun ...
- Android中的Handler,Looper,Message机制
Android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...
- 架构-软件系统体系结构-C/S架构:C/S架构
ylbtech-架构-软件系统体系结构-C/S架构:C/S架构 Client/Server架构,即客户端/服务器架构.是大家熟知的软件系统体系结构,通过将任务合理分配到Client端和Server端, ...
- ssh 登陆免 known_hosts 提示
修改配置文件 “~/.ssh/config”,加上这两行,重启服务器: StrictHostKeyChecking no UserKnownHostsFile /dev/null
- 剑指offer——42最小的K个数
题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 题解: 原以为书中会有好方法,想不到还是排序和STL这两种方法 ...
- Kali Linux 2018 更新源配置
查看添加更新源 编辑sources.list,将kali更新源加入其中 sudo vim /etc/apt/sources.list 国内更新源 #阿里云 deb http://mirrors.ali ...