java class 文件结构的分析

代码:
public class test
{
public static void main(String arg[])
{
System.out.Println("Hello world");
}
}
生成class文件
test Class File Structor:
Magic Number----0XCafeBabe 四个字节
Minor Version---0X0000 两个字节 最小版本号
Max Version---0X002e 两个字节 最大版本号
--------------------------------------------------------------------------------
以上为说明本文件是class 文件及版本 一下是正题
--------------------------------------------------------------------------------
constant_pool_count 0x001d 常量池的大小为28个
--------------------------------------------------------------------------------
常量池开始
--------------------------------------------------------------------------------
注:除01标志(utf-8 表外其余后面的Hex 均为索引)
1 0a 00 06 00 0f 方法常量 0x0006 java/lang/Object 0x000f <init> ()V
2 09 00 10 00 11 字段常量 0x0010 java/lang/System 0x0011 out Ljava/lang/io/PrintStream
3 08 00 12 字符串常量 0x0012 hello wold
4 0a 00 13 00 14 方法常量 0x0013 java/lang/io/PringtStream 0x0014 PrintIn ([Ljava/lang/String;)V
5 07 00 15 类常量 0x0015 test2
6 07 00 16 类常量 0x0016 java/lang/Object
7 01 00 06 ---- <init>
8 01 00 03 ---- ()v
9 01 00 04 ---- code
0a 01 00 0F ---- LineNumberTable
0b 01 00 04 ---- main
0c 01 00 16 ---- ([Ljava/lang/String;)v
0d 01 00 0A ---- sourcefile
0e 01 00 0A ---- test2.java
0f 0c 00 07 00 08 符号引用 0x0007 <init> 0x0008 ()v
10 07 00 17 类常量 0x0017 java/lang/System
11 0c 00 18 00 19 符号引用 0x0018 out 0x0019 Ljava/lang/io/PrintStream;
12 01 00 0B ---- hello wold
13 07 00 1A ---- 类常量 0x001a java/lang/io/PringtStream
14 0c 00 1b 00 1c 符号引用 0x001b PrintIn 0x001c ([Ljava/lang/String;)V
15 01 00 05 ---- test2
16 01 00 10 ---- java/lang/Object
17 01 00 10 ---- java/lang/System
18 01 00 03 ---- out
19 01 00 15 ---- Ljava/lang/io/PrintStream;
1a 01 00 13 ---- java/lang/io/PringtStream
1b 01 00 07 ---- PrintIn
1c 01 00 15 ---- ([Ljava/lang/String;)V
到此常量池结束
对于常量池的总结:
由上面的二进制代码以及常量池类型表的分析
我认为常量池中有三种类型的的常量
一种是tag(类型) 型的常量
如 类常量 type 内容
字段常量 type 类 内容
方法常量 type 类
接口方法常量
这些常量的目的是为了与语言接口
一种是内容型常量
如 utf-8 常量 integer float long double string 等常量
这些常量的目的是为了表达内容
一种是过渡型常量
就是name-type型常量 这种常量的目的就是为了过渡的表示如果无法使用
一个内容常量表示的使用这个常量进行过度。如图
由此的到class 文件常量池的设计原则是
一 所有的类元数据内容都放在utf-8以及其他类型int float 中
二 不同的类元数据类型分别放在 类常量 字段常量 方法常量当中---即类型与内容
分开易于扩展
三 允许嵌套表示 如name-type型
所以常量池的组织的思路类似于XML的组织思路。在.net中就直接使用了XML来描述
元数据
以上为常量池
----------------------------------------------------------------------------
1d 00 21 access_flags 可访问性 acc_Super
1e 00 05 test2
1f 00 06 java/lang/Object
20 00 00 interface count=0
21 00 00 field count=0
22 00 02 method count=2

/
方法一 init方法

00 01 00 07 00 08 00 01 方法信息 0x0001 acc_public 0x0007 <init> 0x0008
()v 0x0001 one atrribute
00 09 00 00 00 1D 0x0009 code 0x0000001d code属性 29个字节
00 01 00 01 00 00 00 05 0x0001 最大栈 0x0001 最大局部变量 0x0000005 code
数5个字节
2a b7 00 01 b1 0x2a aload_0 得到局部变量0位置的对象引用
0xb7 invokespecial 调用制定类的方法
0x0001 java/lang/object.init()v
0xb1 return
00 00 0x0000 exception count=0
00 01 0x0001 attribute count=1
00 0a 00 00 00 06 0x000a LineNumberTable
0x00000006 LineNumberTable属性字节码长6个字节
00 01 00 00 00 01 0x0001 LineNumbertable 数一个
0x0000 star_pc 开始0
0x0001 line_number 开1行

///
方法二 main方法
//
00 09 00 0b 00 0c 00 01 方法信息 0x0009 public&static
0x000b main
0x000c ([Ljava/lang/String;)v
0x0001 属性一
00 09 00 00 00 25 0x0009 code属性
0x00000025 code属性长25字节
00 02 00 01 00 09 0x0002 最大栈数2
0x0001 最大局部变量数1
0x0009 code长9个字节
b2 00 02 12 03 b6 00 04 b1
0xb2 00 02 getstatic #2
得到java/lang/system.out 字段 字段类型 Ljava/lang/io/PrintStream
0x12 03 ldc #03
将hello world 入栈
0xb6 00 04 invokevirtual #04
调用java/lang/io/PrintStream.Printin 方法
0xb1 return
00 00 0x0000 exception count=0
00 01 0x0001 属性数1 个
00 0a 00 00 00 0a 0x000a LineNumberTable
0x0000000a LineNumberTable属性字节码长10个字节
00 02 00 00 00 05 00 08 00 06
0x0002 有两个LineNumberTable
0x0000 star_p 00
0x0005 line_number 05行
0x0008 star_p 08
0x0006 line_number 06行
到此方法信息完毕
---------------------------------------------------------------------------------
00 01 0x0001 表示class有一个属性
00 0d 00 00 00 02 00 0e 0x000d sourcefile 属性
0x00000002 长两个字节
0x000e test2.java
到此class文件结束
--------------------------------------------------------------------------------

总结:
通过对上述class 文件的研究我做了个总结
个人认为设计class 文件的原则如下:
其一 class 文件是按节点方式组织的
每个节点包括两个部分一个是对自身的描述
一个属性

其二 class 文件按层状方式将节点组织起来
其三 全局元数数据 使用常量池描述


节点:
class 文件的节点有
class 节点
self-describe
------------
magicnumber
minor_version
max_version
this_class
super_class
-----------
Attribute
-----------
sourcefile *
innerclass *
field 节点
self-describe
------------
access_flags
name_index
describe_index
-----------
Attribute
-----------
ConstantValue*
Deprecated *
Synthetic *
Method 节点
self-describe
------------
access_flags
name_index
describe_index
-----------
Attribute
-----------
Code*
Deprecated *
Synthetic *
Exception *
code 节点
self-describe
------------
max_stack
max_locals
code
-----------
Attribute
-----------
LineNumberTable*
LocalVariableTable *
Excepion *
基本上class文件就是由上述的节点及属性以及节点大小构成
而且节点嵌套要满足如下层次关系
如下是节点关系图
class 节点
interface 节点
field 节点
method 节点
code 节点
LineNumberTable 属性
注:* 表示可选
节点属性的区别 基本上是节点可以再包含属性,属性只有字描述

延伸:
据我现在所知。net 的PE文件 格式如下
PE头
CLR头
元数据
IL码
其于CLass 文件从可读性而言应该是进步了,
其一 其明确的将数据与数据描述分离出来 形成元数据而没有像 class 文件中的这样
混淆防止 有力于数据扩展
其二 有用于对运行环境的说明的PE头 CLR头 等
对于PE文件格式分析我想在手头有材料和精力的时候再写
我估计PE格式的方式是
将Class,field,Method,interface code以及的自我描述信息都提取出来作为XML 的节点
然后将属性分配到各个节点当中
然后将Code 部分的信息提取出来
以上对于Class文件格式的分析只是一个就事论事的分析,期望能过段时间能有提炼性的分析

问题:
为什么要按照这样的方式设计class 文件呢!?
虚拟机时如何解析这个Class文件 并且将它放当内存中的呢以及如何放的呢?


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiangxigld/archive/2006/02/17/600891.aspx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值