java类加载与class解密

java类加载机制

程序编译

这里要从c语言开始举个例子,我们最开始接触的c语言为什么能够执行呢?

首先c语言的运行需要一下的几个步骤

编译---->汇编---->链接三个步骤。这三个步骤主要完成的工作就是将c语言这种人可以解读的字符串转变为机器能够执行的010101的指令码(关于指令码的执行步骤后面介绍)

https://blog.youkuaiyun.com/u014376961/article/details/87989769

我们都知道汇编其实就是已经在操作计算机中的存储部件了,只不过是在程序诞生之初,人为的去写0101指令简直是一种折磨,所以为了提高开发的效率,出现了汇编这种语言,可以理解为01010的助记符(帮助人开发程序用的符号集合)。

程序运行

c也需要加载

c编译好之后,我们执行c代码的时候,c代码也必须加载到内存中,os才可以将对应的指令交由计算机执行。只不过c的加载进来就是01001的机器码了,os可直接运行。这与java不同。

程序运行过程

刚才说了汇编语言是01010指令码的一种助记符,但是最终程序的执行还是要依赖010101的指令码,010101指令码的执行是这样的。

这就要结合冯 · 诺依曼的计算机思想了,计算机的计算部件主要分为计算单元(物理上为运算器)、控制单元(PC指向程序的下一条指令)、存储单元(存储设备,即内存条)。01010代码是不能直接执行的,还需要经过解析,将指令中的   操作、操作数等解析出来后,交给具体的运算器,这才可以将指令执行完毕。那么计算机的01010指令的执行过程为:

大致看下cpu的内部结构:

指令寄存器(IR ),指令译码器( ID )和操作控制器( OC )

步骤:

  1. 指令指针寄存器即pc,指向下一条指令RAM地址
  2. 控制器将指令指针寄存器中的指令加载到cpu内部的指令寄存器中
  3. cpu内部的指令寄存器将01010指令送到指令译码器中进行译码,将01010指令码中对应的操作数和操作解析出来交给操作控制器。
  4. 操作控制器与运算器交互完成一条指令的执行。

java程序运行

java程序编译之后最终是靠jvm这个虚拟机来执行的,简单来说就是:

  1. 经过类加载后将程序代码.class中存放的代码加载到内存中,也就是常说的类加载
  2. 执行具体方法的时候从元数据中取出来对应的code,注意这里的code已经是jvm可以认识的jvm指令集合
  3. jvm将对应的jvm指令集合再次  解释为  对应的汇编代码
  4. 汇编代码交由OS完成,具体的过程上面已经解释了

一言以蔽之就是:java执行的过程与c大同小异,都是编译后执行,最大的不同就是c编译后可直接运行,java编译后的代码是只能供jvm处理的 .class,OS是不能运行的,因此java还需要再中间再次解释为汇编才可以(jvm指令集合解释为汇编,这也是为什么jvm存在的原因)。

java8中的meta到底和java7 之前的perm区的区别(暂时还不太清楚)

java8之后的meta的一次fullgc的处理过程

https://blog.youkuaiyun.com/caoyuanyenang/article/details/89714220

class解析

class文件

1class文件是javac程序编译好的字节流,他实际上是一个二进制文件,以KA FE BA BE开头

2class文件的大致结构

这个文件中记录了关于这个类的所有信息,

1. KA FE BA BE

2. JAVA 编译版本(javap -verbose xxx.class)

3. 常量池(字段的字符串名称、string类型的字符串)

4. 类的访问控制,就是这个类是public   protected    private(最终都是指向常量池的)

5. 然后是字段表,记录了整个类中所有类字段的信息,包括字段的访问控制(public、private),字段的名称(在常量池中就是一个字符串),字段的属性(比如是否是一个final类型的字段)。还有关于方法签名的描述,即方法的访问控制,方法的名称,方法的参数列表(比如数组类型的参数列表就表示为[I,二维数组就表示为[[I,其中I就表示的是int)

6. 然后是方法表,上面的字段表中只有关于方法签名的表述,但是真正存放具体方法的地方是方法表,方法表中与字段表一样,也是包含访问控制,方法名称,方法签名,方法返回值。但是这里的方法表中有一个code的属性,这个属性里面存放的就是真实方法里面的代码,这是区别与字段表最大的不同。

7. 然后是属性表,属性表其实不是作为一个单独的表存在,而是与签名的字段表和方法表配合存在的,因为有一些属性是额外记录在属性表的,字段表和方法表中只有一个指向属性表的指针。

举例

比如方法表中的一个必不可少的属性code就放在对应方法的属性表里面,所以真实的方法表里面是不存放code属性的。程序代码在真正执行的时候需要从方法表的code属性中取出代码,然后jvm执行具体的jvm指令集。

再比如字段表中一个重要的属性就是final属性,比如类中有一个字段为

final String name = "sam"

name这个字段表就会有一个属性表,对应的属性表中就会有一个ConstantValue属性(摘自《深入理解java虚拟机6.3.6方法表集合倒数第二段》),用来执行常量池中的某一常亮,所以编译阶段,jvm就把这个属性给填好了。

class对象

刚才的字节码文件(class文件)描述完毕后,对class里面存放的东西有了一个比较清楚的认识,现在想下刚才类加载的顺序

1根据类的全限定名称确定一个class文件的字节流,其实就是要将这个文件读取进来,通过流的方式

2将这个class文件的二进制流装在到内存中,其实就是将这个流读取到内存中来

3创建二进制流对应的class对象,实际上整个类加载阶段就干了这个一件事情,刚才前两部其实一句话概况就是:

将class文件读进来,然后读进来这个字节码的东西需要有个地方存,那么这个class对象就负责存这些信息,只不过有一些信息class对象中并不直接存放,只存放了meta区域的指针(地址),这也就印证了之前的一句话,使用class对象创建类的实例对象。简单概况就是class对象就是字节码文件的内存反应,只不过有一些内容没有直接放在class对象中,因为这个class对象是放在堆内存中的,meta信息是放在meta区域的,class对象中肯定有指向meta区域的指针存在,但是class对象存放了大多数的类信息和类信息的入口。我们可以通过java公共类Class提供的方法就可以看出来

稍微想一下就知道,为什么这个class对象就能提供这么多的方法呢,这么多年才明白,class对象就是class字节码文件的内存映射,字节码里面有啥这个class对象就能帮你取到啥,所以class其实就是你的java文件里面写的所有的东西,只不过是jvm需要将人写的东西装换为机器能认识的东西,所以需要这个class对象。

class对象到底和class文件有啥关联(no)

之前一直没弄明白类加载的时候在加载阶段过程为

通过类的全限定名称找到一个类的(也就是class文件的二进制流)

将二进制流装载到内存中

创建class对象,作为所有访问类元数据的地址(这句话很重要)

现在解释一下这两者之间的区别:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值