Java文件字节码内容总结1

1. 特点:

    java字节码文件(即类文件)是编译后生成的,特点1:就是java的类文件文件不像C文件编译时经过链接阶段,所以java的类文件不包含对象在内存中的状态。特点2:java的字节码文件以单个字节作为基本单位,非常紧凑,不存储多余的内容。特点3:字节码文件数据类型只有两种:无符号数和表,其中无符号数长度是固定的,可以为1,2,4,8个字节,表的长度不固定,类似于结构体,由无符号数和其他表组成,来表示复杂的数据---这段回忆时没记起来,详细内容参考周志明的《深入理解java虚拟机》。

2. 如何获取字节码文件?以及如何查看字节码文件的内容?

   java文件编译后生成.class的字节码文件,jdk中自带的命令javap -verbose 类名字  就可以将类的字节码内容输出到名令屏上。

例如,写一个简单的类,只有两个变量

class example{
   int a = 1;
   int b = 2;
   }


F:\javaClassTest>javap -verbose example
Compiled from "example.java"
class example extends java.lang.Object
  SourceFile: "example.java"
  minor version: 0
  major version: 49
  Constant pool:
const #1 = Method       #5.#15; //  java/lang/Object."<init>":()V
const #2 = Field        #4.#16; //  example.a:I
const #3 = Field        #4.#17; //  example.b:I
const #4 = class        #18;    //  example
const #5 = class        #19;    //  java/lang/Object
const #6 = Asciz        a;
const #7 = Asciz        I;
const #8 = Asciz        b;
const #9 = Asciz        <init>;
const #10 = Asciz       ()V;
const #11 = Asciz       Code;
const #12 = Asciz       LineNumberTable;
const #13 = Asciz       SourceFile;
const #14 = Asciz       example.java;
const #15 = NameAndType #9:#10;//  "<init>":()V
const #16 = NameAndType #6:#7;//  a:I
const #17 = NameAndType #8:#7;//  b:I
const #18 = Asciz       example;
const #19 = Asciz       java/lang/Object;

{
int a;
int b;
example();
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   iconst_1
   6:   putfield        #2; //Field a:I
   9:   aload_0
   10:  iconst_2
   11:  putfield        #3; //Field b:I
   14:  return
  LineNumberTable:
   line 1: 0
   line 2: 4
   line 3: 9
}


3.类文件的组成

3.1 魔数

      ---也就是java虚拟机用来识别一个文件是否是java字节码文件的标识,位于字节码文件的开始部分,占据4个字节,以16进制的标识方式就是CAFEBABE,这个是约定好的,应该很好理解,就像写信和看信的人约定一个密码一样。

3.2 JDK版本

    因为字节码文件是使用JDK编译而成的,自然而然就涉及到JDK的版本问题,虽然软件开发都是向前兼容,也即是高版本的JDK能够运行低版本的JDK编译的字节码文件,但是反过来是不成的,就会爆出常见的UnsupportClassVersion异常。

    那么虚拟机是如何识别出字节码文件的JDK版本的呢?class文件的魔数后面的4个字节代表了字节码文件使用的JDK版本,其中前两个字节表示子版本号,后两个字节表示主版本号,如上面的例子中为00 00 00 31,00 00代表子版本号为0, 而00 31 换算成十进制结果是49,这里有个对应关系

jdk1.4 对应48 (00 30),

jdk1.5 对应49,(00 31),

jdk1.6 对应50,(00 32),

jdk1.7 对应51,(00 33),

上面的对应关系指的是编译时不加任何额外参数的前提下,可以在自己的机器上用java -version来对比验证下。

3.3 常量池

      常量池相当于类的静态描述,运行时对应方法区中的内容,它描述了类的名字,变量的名字、类型 ,方法的名字、类型、返回值等内容,可以说是被用到最多的地方了。因为常量池的长度不固定,所以先以一个2字节的代表长度的内容开始。上面例子中00 14,十进制长度内容为20(实际上只有20-1=19个常量,因为从1开始计数,0位有特殊用途)。--上面这句理解现在看来有问题,常量池相当于类描述的基础,是作料级别的,下面类索引、父类索引、接口集合、字段、方法才是一一确定类的各个组成部分。

     常量池里内容有12种类型,整形字面量、浮点型字面量、字符串类型字面量、长整形字面量、双精度浮点型字面量、utf-8编码的字符串;类或接口的符号引用、字段的符号引用、类中方法的符号引用、接口中方法的符号引用、字段或者方法的部分符号引用---说明,前面6个都是字面量,类似于java中的常量(用final修饰符)的,只是utf-8编码的字符串是最常用的,因为类文件不涉及内存中的存储结构,所以最终都要落实到符号描述上来。以下面Class为例:

Class example{
int num ;
String name ;
Public int addNum(int num){
Return ++num;
}
}

要描述类example,首先确定它的类型是类,然后在确定名字就可以了。对于变量,example.num(int类型),分为它属于的类,和变量的名称和类型num(int类型);对于方法 example.addNum(int num,返回int)

上图是自己对常量池抽象设计的一个理解。可以看到上面结构中不包括public,private等访问控制符的内容,因为在类文件中访问控制符有单独的部分来实现,后面能够看到。

   再回到类文件的解析上来,前面说了第9,10个字节代表常量池中常量的长度,但是常量的类型有上面说的12种,只知道总的常量个数并不能确定每个常量对应的字节码内容,因此接下来每个常量的开始都是由一个单独的字节来代表常量的类型,如utf-8编码的字符串”的标志是1,而“类或接口的符号引用”标志是7,每个类型都有自己确定的结构。以类或接口的符号引用”为例,共占有3个字节,第一个字节是表示类型,后两个字节表示类名字的索引。这样,总的变量个数确定,每个变量的类型和结构、长度都是确定的,java虚拟机再读入字节码解析的时候也就是可以正确的解析了。

前面Class类文件的字节码一段如下图:

01 00 06 3C 69 6E 69 74 3E ,其中01代表的是“utf-8编码的字符串”,00 06代表的是这个字符串的长度是6个字节,3C 69 6E 69 74 3E这6个字节代表的就是这个字符串的内容,因为是ascii码,每个字节对应一个字符,翻译过来就是<init>



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值