- 浏览: 1657958 次
- 性别:
文章分类
- 全部博客 (2929)
- 非技术 (18)
- Eclipse (11)
- JAVA (31)
- 正则表达式 (0)
- J2EE (4)
- DOS命令 (2)
- WEB前端 (52)
- JavaScript (69)
- 数据库 (8)
- 设计模式 (0)
- JFreechart (1)
- 操作系统 (1)
- 互联网 (10)
- EasyMock (1)
- jQuery (5)
- Struts2 (12)
- Spring (24)
- 浏览器 (16)
- OGNL (1)
- WebService (12)
- OSGi (14)
- 软件 (10)
- Tomcat (2)
- Ext (3)
- SiteMesh (2)
- 开源软件 (2)
- Hibernate (2)
- Quartz (6)
- iBatis (2)
最新评论
1.目的
大
型软件系统开发时,某些Java组件可能涉及到多种数据库或中间件系统的连接和应用,例如一个数据传递组件需要从DB2中读取数据,并将数据通过中间件
WebSphere
MQ发送到其他系统,这类组件功能单一,但却需要连接多种第三方产品,使得程序员的单元测试变的非常不便,程序员不得不注视或修改部分源代码,或者在本地
安装所需第三方产品。无疑这两种选择都是痛苦的。
基于以上的不便,本文开发了解析Java Class文件程序,目的是将第三方产品API的Class文件转换为Java源文件(不包括Java类的方法实现),在源文件的各种程序所需的方法里实 现一些简单的语句,例如数据库连接方法永远返回true,获得数据方法永远返回 ”Hello world” 等,用JDK重新编译转换后的Java源文件,来替换真正的API 文件,这样程序员在UT测试时,无需修改源代码,也无需安装任何产品,并且能通过修改替换的API Java源文件实施各种UT测试。
为 了实现以上需求,必须先要了解Java Class文件格式。Java虚拟机识别的class文件格式包含Java虚拟机指令(或者bytecodes)和一个符号表以及其他的辅助信息。本文将 使用VC++语言解析Java Class文件符号表,逆向生成Java源代码结构。如图1:
图1
之所以使用VC++而不使用Java的主要是因为VC++界面开发简单;运行速度快,不需要虚拟机;需要用指针建立复杂的数据结构。
2.实现
实现该工具的过程如下:
1.解析Class文件,从Class文件中读取数据并保存到称为ClassFile结构体中;
2.解析ClassFile结构体,生成源代码字符串;
3.将字符串显示到视图中。
2.1 解析Class文件
为实现第1步,首先需要了解Class文件格式规范,参考《Java虚拟机规范》第四章class文件格式,总结class文件的数据结构如图2。
2.1.1 Class文件格式
Class文件格式ClassFile结构体的C语言描述如下:
struct ClassFile
{
u4 magic; //识别Class文件格式,具体值为0xCAFEBABE,
u2 minor_version; // Class文件格式副版本号,
u2 major_version; // Class文件格式主版本号,
u2 constant_pool_count; // 常数表项个数,
cp_info **constant_pool;// 常数表,又称变长符号表,
u2 access_flags; //Class的声明中使用的修饰符掩码,
u2 this_class; //常数表索引,索引内保存类名或接口名,
u2 super_class; //常数表索引,索引内保存父类名,
u2 interfaces_count; //超接口个数,
u2 *interfaces; //常数表索引,各超接口名称,
u2 fields_count; //类的域个数,
field_info **fields; //域数据,包括属性名称索引,//域修饰符掩码等,
u2 methods_count; //方法个数,
method_info **methods;//方法数据,包括方法名称索引,方法修饰符掩码等,
u2 attributes_count; //类附加属性个数,
attribute_info **attributes; //类附加属性数据,包括源文件名等。
};
其中u2为unsigned short,u4为unsigned long:
typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned long u4;
cp_info **constant_pool是常量表的指针数组,指针数组个数为constant_pool_count,结构体cp_info为
struct cp_info
{
u1 tag; //常数表数据类型
u1 *info; //常数表数据
};
常数表数据类型Tag定义如下:
#define CONSTANT_Class 7
#define CONSTANT_Fieldref 9
#define CONSTANT_Methodref 10
#define CONSTANT_InterfaceMethodref 11
#define CONSTANT_String 8
#define CONSTANT_Integer 3
#define CONSTANT_Float 4
#define CONSTANT_Long 5
#define CONSTANT_Double 6
#define CONSTANT_NameAndType 12
#define CONSTANT_Utf8 1
每种类型对应一个结构体保存该类型数据,例如CONSTANT_Class 的info指针指向的数据类型应为CONSTANT_Class_info
struct CONSTANT_Class_info
{
u1 tag;
u2 name_index;
};
图2
CONSTANT_Utf8的info指针指向的数据类型应为CONSTANT_Utf8_info
struct CONSTANT_Utf8_info
{
u1 tag;
u2 length;
u1 *bytes;
};
Tag和info的详细说明参考《Java虚拟机规范》第四章4.4节。
access_flags为类修饰符掩码,域与方法都有各自的修饰符掩码。
#define ACC_PUBLIC 0x0001
#define ACC_PRIVATE 0x0002
#define ACC_PROTECTED 0x0004
#define ACC_STATIC 0x0008
#define ACC_FINAL 0x0010
#define ACC_SYNCHRONIZED 0x0020
#define ACC_SUPER 0x0020
#define ACC_VOLATILE 0x0040
#define ACC_TRANSIENT 0x0080
#define ACC_NATIVE 0x0100
#define ACC_INTERFACE 0x0200
#define ACC_ABSTRACT 0x0400
#define ACC_STRICT 0x0800
例如类的修饰符为public abstract则access_flags的值为ACC_PUBLIC | ACC_ABSTRACT=0x0401。
this_class的值是常数表的索引,索引的info内保存类或接口名。例如类名为com.sum.java.swing.SwingUtitlities2在info保存为com/sum/java/swing/SwingUtitlities2
super_class的值是常数表的索引,索引的info内保存超类名,在info内保存形式和类名相同。
interfaces是数组,数组个数为interfaces_count,数组内的元素为常数表的索引,索引的info内保存超接口名,在info内保存形式和类名相同。
field_info **fields是类域数据的指针数组,指针数组个数为fields_count,结构体field_info定义如下:
struct field_info
{
u2 access_flags; //域修饰符掩码
u2 name_index; //域名在常数表内的索引
u2 descriptor_index; //域的描述符,其值是常数表内的索引
u2 attributes_count; //域的属性个数
attribute_info **attributes; //域的属性数据,即域的值
};
例如一个域定义如下:
private final static byte UNSET=127;
则该域的修饰符掩码值为:ACC_PRIVATE | ACC_STATIC | ACC_FINAL=0x001A
常 数表内name_index索引内保存数据为UNSET,常数表内descriptor_index索引内保存的数据为B(B表示byte, 其他类型参考《Java虚拟机规范》第四章4.3.2节)。attributes_count的值为1,其中attributes是指针数组。指针数组个 数为attributes_count,在此为1,attribute_info结构体如下:
struct attribute_info
{
u2 attribute_name_index; //常数表内索引
u4 attribute_length; //属性长度
u1 *info; //根据属性类型不同而值不同
};
attribute_info 可以转换(cast)为多种类型 ConstantValue_attribute,Exceptions_attribute,LineNumberTable_attribute,LocalVariableTable_attribute,Code_attribute 等。
因为域的属性只有一种:ConstantValue_attribute,因此此结构体转换为
struct ConstantValue_attribute
{
u2 attribute_name_index; //常数表内索引
u4 attribute_length; //属性长度值,永远为2
u2 constantvalue_index; //常数表内索引,保存域的值
//在此例中,常数表内保存的值为127
};
method_info **methods是方法数据的指针数组,指针数组个数为methods_count,结构体method_info定义如下:
struct method_info
{
u2 access_flags; //方法修饰符掩码
u2 name_index; //方法名在常数表内的索引
u2 descriptor_index; //方法描述符,其值是常数表内的索引
u2 attributes_count; //方法的属性个数
attribute_info **attributes; //方法的属性数据,
//保存方法实现的Bytecode和异常处理
};
例如一个方法定义如下:
public static boolean canAccessSystemClipboard(){
...
}
则 access_flags的值为 ACC_PUBLIC | ACC_STATIC =0x0009,常数表内name_index索引内保存数据为canAccessSystemClipboard,常数表内 descriptor_index索引内保存数据为()Z;(括号表示方法参数,Z表示返回值为布尔型,详细说明参照《Java虚拟机规范》第四章 4.3.2节)。attribute_info **attributes是方法的属性指针数组,个数为attributes_count,数组内保存的是常数表索引,info为 Code_attribute或Exceptions_attribute。
本文不解析方法内容,因此忽略Code_attribute和Exceptions_attribute的内容。
ClassFile结构体中的attribute_info **attributes是附加属性数组指针,个数为attributes_count,本文只识别SourceFile属性。
struct SourceFile_attribute
{
u2 attribute_name_index; //常数表内索引
u4 attribute_length; //属性长度值,永远为2
u2 sourcefile_index; //常数表内索引,info保存源文件名
};
例如com.sum.java.swing.SwingUtitlities2类的源文件名为SwingUtitlities2.java。
以上是本文需要解析的Class文件格式。
2.1.2 读取数据
定 义CJavaClass类完成解析Class文件,生成Java源程序字符串。使用VC++的MFC类CFile从Class文件读取数据。例如:用16 进制编辑器打开Class文件,如图3,前4个byte分别是CA FE BA BE,使用CFile::Read(tmp,sizeof(u4))读取后,tmp的值为0xBEBAFECA,所以需要位转换。定义以下方法从文件读取 定长数据:
void readu1(u1 *buff);
void readu2(u2 *buff);
void readu4(u4 *buff);
定义如下方法读取变长数据。
void readun(void *buff,u4 len);
读取的u2和u4的数据需要位转换:
U1 [0]
U1 [1]
U1 [1]
U1 [0]
U2:
U1 [0]
U1 [1]
U1 [3]
U4:
U1 [2]
U1 [3]
U1 [2]
U1 [0]
U1 [1]
调用void readu4(u4 *buff);后buff的值为0xCAFEBABE,该值为ClassFile的magic,识别该文件是Java Class文件。
图3
magic的后面是Class格式的版本号,图3的版本为0x00000030=0.48。版本后面是常数表的元素个数,图3的常数表的元素个数为 0xD2=210个。常数表的元素个数之后如ClassFile结构体定义的常数表,类信息,接口信息,域信息,方法信息和附加属性等。
2.2 生成Java源文件
解析Class文件后,生产ClassFile结构体。遍历该结构体数据,则可根据Java语言规范生成Java源文件。例如根据ClassFile的
access_flags值获得Java类的修饰符,其中access是CArray<CString,CString&>,保存类
所有的修饰符:
if((flag & ACC_PUBLIC )==ACC_PUBLIC)
{
access.Add(CString("public"));
}
if((flag & ACC_PRIVATE)==ACC_PRIVATE)
{
access.Add(CString("private"));
}
if((flag & ACC_PROTECTED)==ACC_PROTECTED)
{
access.Add(CString("protected"));
}
…
2.3显示视图
将获得的Java源代码显示在MFC的CScrollView视图非常简单,可以添加一些关键字颜色,例如注释显示为草绿色等,如图4。
图4
3.总结
本文根据《Java虚拟机规范》开发了解析Java Class文件格式,并生成Java源代码结构的工具。其优点是:
1.脱离Java 虚拟机或Java开发环境;
2.可查阅没有Java源代码的Class文件的内容;
3.为一些复杂的Java Jar包生成相同类名的替代类,方便开发调试。例如,用返回固定字符串的java源文件更换需要网络链接的相同java类,有助于本地运行与调试。
缺点是:
1.由于没有反编译Bytecode,工具生成的部分Java源文件需要手动添加一些Java属性值;
2.Java源文件内的所需要使用的Java方法内容需要程序员手动实现。
摘自:http://blog.csdn.net/zhy05/archive/2007/09/25/1800309.aspx
发表评论
-
使用Java 动态代理实现AOP
2009-07-22 14:29 607目前整个开发社区对AOP(Aspect Oriented P ... -
Java中用动态代理类实现记忆功能
2009-07-22 14:30 703记忆是衍生自lisp,python, ... -
JAVA动态代理实现方法
2009-07-22 14:31 694在目前的Java开发包中包含了对动态代理的支持,但是其实现只支 ... -
对代理模式与Java动态代理类的理解(转)
2009-07-22 14:32 7661. 代理模式 代理模式的作用是:为其他对象 ... -
十年与java 相关的名字
2009-07-22 17:12 732RickardOberg:J2EE奇才 文/ ... -
搞懂java中的synchronized关键字
2009-07-28 17:48 607实际上,我关于java的基 ... -
字符串转化为unicode编码
2009-07-31 16:16 901package com.util; import java. ... -
移位运算符的规则及其数学意义
2009-07-31 18:02 779移位运算符就是在二进制的基础上对数字进行平移。按照平移的方 ... -
几个谜题,深入的了解java
2009-08-03 17:02 731在2009年的JavaOne大会上,Joshua Bloch和 ... -
一、我对java中编码的理解(摘)
2009-08-06 09:17 6241. 编码的产生 对电 ... -
四、深入下package,import:(摘)
2009-08-06 09:18 706注:因package,import涉及较多内容,另开一个帖子了 ... -
三、我对java中类路径的理解(摘)
2009-08-06 09:18 529Java中的类路径分“编译后的存放路径” 和 “运行时的查找路 ... -
二、我对java中类装载的理解(摘)
2009-08-06 09:18 7751.Java中的所有类,必须 ... -
关于 JavaBean 规范你还是应该知道的二三事
2009-08-06 09:22 823作为 Java 程序员,对于 JavaBean 也许你会说再熟 ... -
synchronized(this)的几个简单示例
2009-08-06 10:31 822一、当两个并发线程访问同一个对象object中的这个synch ... -
java压缩对象 与 对象的序列化
2009-08-07 17:39 668gzip是目前广泛应用的一种压缩方式,它具有很高的压缩比和压缩 ... -
Java常见问题集锦
2009-08-12 12:22 681如何设置Java 2(JDK1.2)的环境变量? 哪些Jav ... -
JavaFX尝鲜
2009-08-17 17:24 506java6出来以后,其一大 ... -
Java在不同环境下获取当前路径的方法--this.getClass().getResource("")
2009-08-17 17:24 7061. 在Servlet/Filter等Servlet web环 ... -
JAVA进阶:VO(DTO)与PO(DAO)之间的转换
2009-08-26 13:58 898PO即 Persistence Object VO ...
相关推荐
Java Class文件解析是Java开发中的一个重要概念,它涉及到Java虚拟机(JVM)如何理解和执行程序的核心机制。这篇博文的链接虽然无法直接访问,但从标题和标签我们可以推测,内容可能涵盖了对Java字节码的深入理解和...
首先,Class文件是以二进制格式存储的,其结构遵循一种固定的布局,这种布局被称为“魔数”(Magic Number)开始,用来标识这是Java的Class文件。紧随其后的是版本信息,包括类文件的版本号和JVM的版本号,这些信息...
在本主题中,我们将探讨如何使用Python来解析Java的Class文件,并对其进行简单的执行。这是一项有趣的技术,可以帮助我们理解Java字节码的工作原理,同时也可以在Python环境中运行Java代码。 首先,Java的Class文件...
总之,Java Class文件是Java程序执行的关键,通过编译过程将源代码转化为JVM能理解的二进制格式。了解其结构和编译原理对于优化代码和调试问题都十分有益。使用像jclasslib这样的工具,我们可以直观地查看和分析...
Java Class文件遵循特定的文件格式,这个格式由一系列的8位字节构成,包括魔数(Magic Number)、版本信息、常量池、访问标志、类和父类索引、接口索引集合、字段表集合、方法表集合、属性表集合等。这些结构共同...
Java Class文件是Java程序编译后的二进制格式,它包含了类和接口的定义、方法体、常量池等信息,但这些信息是以机器可读的字节码形式存在,对于人类来说不易理解。为了查看和理解Class文件内部的源代码,我们就需要...
### Java对MHT文件解析及内容抓取技术详解 #### 一、引言 MHT(Mime HTML)文件是一种将HTML文档与嵌入资源(如图像、样式表等)合并为一个文件的格式,方便在网络上传输。本文将详细介绍如何使用Java语言解析MHT...
Java Class文件查看器是一款专为Java开发者设计的实用工具,它允许用户查看和分析.class文件,这是Java编译器将源代码编译后的二进制形式。了解如何使用这类工具对于理解和调试Java应用程序至关重要,尤其是在处理已...
Java解析JSON文件是Java开发中常见的一项任务,特别是在与Web服务交互或处理API响应时。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,因其简洁和易于阅读及编写的特点,被广泛应用于网络数据传输...
在深入讲解Class文件格式之前,我们需要理解Java字节码的概念,它是一种平台无关的中间语言,使得Java程序可以在任何支持JVM的设备上运行。 1. **总体格式** Class文件的结构遵循一个固定的模板,由多个字段组成...
Java class文件和jar文件是Java程序的二进制表示形式,它们包含了编译后的字节码,用于JVM(Java虚拟机)执行。在开发和调试过程中,有时我们需要查看源代码,但原始的.java源文件可能丢失或者不可用。这时,反编译...
本文将深入探讨如何在Java中解析YAML文件,包括依赖管理、封装解析类以及源码分析。 首先,为了在Java项目中使用YAML解析功能,我们需要引入相关的库。在Maven项目中,可以在`pom.xml`文件中添加SnakeYAML的依赖: ...
### JavaClass文件的结构分析及其校验 #### 引言 随着Java技术的不断发展与广泛应用,JavaClass文件作为Java程序的基础组成部分,其结构与验证机制的重要性日益凸显。本文旨在深入探讨JavaClass文件的结构特点,并...
class文件是Java源代码经过JVM(Java Virtual Machine)编译后的二进制格式,它包含了类的结构、方法、变量等信息。本篇文章将详细探讨如何解析这些class文件,以及在Android开发中可能遇到的相关问题。 1. **Java...
本项目“基于Go的Java Class文件解析工具”旨在利用Go语言开发一个工具,用于解析和理解这些二进制文件,帮助开发者更好地分析和理解Java程序的底层结构。 Go语言是一种静态类型的、编译型的、垃圾回收的语言,具有...
一个简单的分析工具,用于分析”.class/.cap/.exp”格式的Java文件。 对于CAP文件,支持version 2.1 and 2.2. 适用于JCVM的学习。 使用工具时,需保证“C:\Program Files\WinZip\WINZIP32.EXE”存在,用于解压CAP...
`JavaDecompiler`这个标题暗示我们将探讨如何使用Java反编译器来打开和解析.class文件。 Java类文件是Java虚拟机(JVM)执行的二进制格式,包含了程序的指令、常量池、字段和方法定义等信息。然而,这些信息对于...
class文件解析器class文件解析器class文件解析器
总结来说,Java class文件格式的数据类型是理解JVM如何解析和执行Java程序的关键。CONSTANT_Class_info和CONSTANT_Fieldref_info分别用于描述类和字段的符号引用,它们在class文件的常量池中起着至关重要的作用。...
Class文件的格式是严格定义的,确保了JVM能够正确解析和执行其中的代码。在JVM规范第四章中,详细描述了Class文件的结构,主要包括以下几个关键部分: 1. **魔数(Magic Number)**:每个Class文件的开头都有一个4...