class文件是编译器编译之后供虚拟机解释执行的二进制字节码文件,不只是java, 
比如Groovy,JRuby,FANTOM,Jython,和Scala。这是在jvm上运行的5大脚本语言。下面就带你分析一个class的字节码文件,class文件只有无符号数和表两种基本的数据类型,u1,u2,u4,u8代表1个字节,2个字节,4个字节,8个字节的无符号数。表是由无符号数和表组合而成的结构,说表觉得不好理解的话,可以认为就是按照规定排列无符号数来描述的一种结构。 
编译版本:jdk1.7 
class打开工具:16进制编辑器winHex 
编译代码:

import java.io.Serializable;


public class Amethod implements Serializable{
    private int j;
    public int getJ(){
        return j;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

class文件打开: 
Amethod.class 
从这里我们可以看到,class以8个字节为基础单位,无任何分隔符

常量池:使用命令 javap -verbose Amethod,常量池只分析一个(其他的分析方法一致),其他的就通过这个命令来看 
这里写图片描述

1.魔数 
开头的cafebabe(咖啡宝贝?java的杯子装咖啡的logo),表明这是一个可以被jvm执行的class文件,仅仅通过后缀名来辨别文件的类型是不安全的,因为你可以随意修改后缀名,jpg等等也有自己的魔数,可以打开看一下: 
这里写图片描述 
因为有魔数的存在,即使*.jpg被修改成了*.1234567,仍然可以用打开。 
2.版本号 
紧接着的00000033代表这个class文件被编译的版本号,0000是次版本号,0033是主版本号,33转换成10进制就是51,jdk1.7可以编译的最大版本号就是51。虚拟机只能编译版本号比自己支持的最大版本号小的,超过了虚拟机支持的最大版本号,会抛出java.lang.UnsupportedClassVersionError。 
3.常量池 
接着就是常量池,常量池里存放的是字面常量(literal)和符号引用(symbolic references),字面量比较接近java中常量的概念,如文本字符串,声明为final的常量值等。符号引用属于编译原理方便的概念,包含以下三个常量; 
3.1 类和接口的全限定名 
3.2 字段的名称和描述符 
3.3 方法的名称和描述符

每一个常量都是一个表,或者说都有他们自己的结构,所有常量结构的共同点是它们的第一位都是一个u1类型的标志位,用来标志这个常量的类型。我们来看这个具体的例子: 
0x0018 :用来指明常量的个数,每个class的常量个数都不一样,需要指明,这里表示有23个常量。为什么不是24,0位空出来了表示null,把不指向任何值的常量池的索引指向这个null。

这里写图片描述

继续分析,接下来是07,这个是常量的标志类型,查上表标志是7的,我们看到这个类或接口的符号引用,CONSTANT_Class_info,以_info结尾的表示这是个表,表结构如下: 
这里写图片描述 
tag:07是标志位,占一个字节,name_index占两个字节,那么从07开始向后看两个字节,0002,表示指向常量池中的第二个常量,紧接着的就是第二个常量,那么继续,01,标志位是01的查表可知是UTF-8编码的字符串,CONSTANT_UTF8_INFO,以_info结尾,也是一个表,表结构如下: 
这里写图片描述 
tag:01,占一个字节 
length:类型是u2,表示占两个字节,01后面的两个字节是0007,表示长度为7, 
bytes:以utf-8缩略码表示的字符串,占一个字节,数量为length,length我们已经知道是7,那么后面的7个字节就表示这个常量的值,向后看7个字节: 
41 6D 65 74 68 6F 64,查ascii码表16进制: 
41:A 
6D:M 
65:E 
74:T 
68:H 
6F:O 
64:D 
合起来就是Amethod,是不是类的全限定名!这里我没有将Amethod.java放在包下面,所以全限定名就是Amethod,假如我把这个类放在com.txx.csdn这个包下面,那么这个值就应该是com/txx/csdn/Amethod