- 浏览: 84707 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
zhtch_123:
hold_on 写道zhtch_123 写道可以,使用apk的 ...
Android插件式开发(一) -
hold_on:
zhtch_123 写道可以,使用apk的静默安装那还是要安装 ...
Android插件式开发(一) -
zhtch_123:
可以,使用apk的静默安装
Android插件式开发(一) -
hold_on:
xingzhe321655 写道这个思路不错,但是每安装一个插 ...
Android插件式开发(一) -
zhtch_123:
很久没有用了,现在要用了,来复习一下。不论ssh怎么更新版本, ...
SSH 架构
Java Class文件结构分析
学习 Java 虚拟机对于理解 AOP ,反射,并发同步、垃圾回收、代码优化等方面都会有不少帮助,有时候还是有必要对底层的原理做一下了解。不过看起来确实比较费解。可以一步一步来,能看懂多少是多少。
Java 虚拟机可以从 class 字节码文件、类装载体系结构、对象生命周期、执行引擎、 API 规范等几个方面来学习。 Class 文件是 java 虚拟机的基础,从 class 文件结构中可以学习到 java 虚拟机的一些基本原理。
本文主要介绍 class 文件的设计结构,为后面的话题打下一个基础。 ( 主要参考了深入 java 虚拟机这本书和网上资料 )
1. ClassFile 基本定义
Classfile 是一个连续的 8 位字节二进制流,数据项按照顺序存储在 class 文件中,相邻项没有间隔,占多字节空间的项时,高位在前。
ClassFile 文件格式是固定的,按照顺序
名称 |
长度 |
描述 |
备注 |
majic |
4 个字节 |
魔数 :0xCAFEBABE |
Od –x 命令可以看到。这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件 |
Minor_version 和 major_version |
分别 2 字节 |
主次版本号: Class 文件格式一旦发生变化,版本号也会随之变化。 |
如果 class 文件版本号超出了处理范围, java 虚拟机将不会处理该文件。 |
Constantpool_count,constanpool |
不固定 |
常量池:包含了文件中类和接口相关的常量。文字字符串、 final 变量值、类名和方法名的常量。常量池的大均占到了整个类大小的 60% 左右。 |
入口列表的形式来存储。每个常量池入口都从一个长度为一个字节的标志开始。除了字面常量还可以容纳字段名称、方法名称和类的全限名等。 |
Access_flags |
2 字节 |
访问标志 : 定义了类或接口 |
指明了是类还是接口、是抽象还是具体。公共、 final 等修饰符。 |
This_class |
2 字节 |
本身是一个常量池的索引,指向了常量池中该类全限定名的常量池入口 |
|
Super_class |
2 字节 |
指向父类全限定名 |
|
Interface_count 和 interfaces |
不固定 |
该类实现的接口数量, interfaces 包含了由该类实现的接口的常量池引用。 |
|
FiledsCount 和 fileds |
不固定 |
字段数量和字段的信息表。描述了字段的类型、描述符等。 |
|
Methods_count 和 Mechods |
不固定 |
方法总数和方法本身。使用 ASM 进行 AOP 编程,通常是通过调整 Method 中的指令来实现的。 |
每一个方法都会有一个 Mechod_info 表,改表记录了方法的方法名、描述符、返回类型。局部变量表,字节码序列等。 |
Attributes_count 和 Attributes |
不固定 |
属性总数和属性本身。写出了 |
|
2. CLassFile 详细结构
根据如上格式定义成结构体如下
( 以下内容参考了文章 http://hi.baidu.com/52dege/blog/item/f33a3cf4092491dbf3d3854f.html ) :
ClassFile {
u4 magic; // 必须为 : 0xCAFEBABE
u2 minor_version;
u2 major_version; //CLASS 文件结构主次版本号 JAVA2 支持 45.0-46.0
u2 constant_pool_count; // 记录常量信息
cp_info constant_pool[constant_pool_count-1]; // 计数从 1 开始
u2 access_flags; //class/interface 访问权限
u2 this_class; // 指向 constant_poll 中的有效索引值
u2 super_class; //0 或指向 constant_poll 中的有效索引值 , 对于 interface 必须为非 0
u2 interfaces_count; //superinterfaces 的个数
u2 interfaces[interfaces_count]; // 计数 [0,count-1) 对应 constant_pool 中的一个索引值
u2 fields_count;
field_info fields[fields_count]; // 主要用于记录 class 及实例中的变量
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
对于上面的 cp_info constant_pool[constant_pool_count-1], 是一个 cp_info 结构体的系列。
cp_info {
u1 tag;
u1 info[];
}
在 java 虚拟机规范里面一共定义了 12 种 cp_info , tag 值从 1 到 12 :
CONSTANT_Utf8 1
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_Class 7
CONSTANT_String 8
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_NameAndType 12
( 好像没有 2 ???书上暂时也没看到。 )
对应的 cp_info 结构分别如下:
CONSTANT_Utf8
CONSTANT_Utf8_info {
u1 tag; //tag 值等于 1
u2 length;
u1 bytes[length];// 存储字符串数组
}
这是非常核心的一个 cp_info, 所有的字符串都由它存储表示。包括文字字符串、全限定名、字段名、方法名、描述符等都指向它。
CONSTANT_Integer
CONSTANT_Integer_info {
u1 tag; //tag 值等于 3
u4 bytes;// 按照高位在前格式存储 int 类型值
}
CONSTANT_Float
CONSTANT_Float_info {
u1 tag; //tag 值等于 4
u4 bytes;
}
CONSTANT_Long
CONSTANT_Long_info {
u1 tag; //tag 值等于 5
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double
CONSTANT_Double_info {
u1 tag; //tag 值等于 6
u4 high_bytes;
u4 low_bytes
}
CONSTANT_Class ( 类全限定名 )
CONSTANT_Class_info {
u1 tag; //tag=7
u2 name_index; // 指向包含全限定名字符串的一个 CONSTANT_Utf8_info
}
CONSTANT_String
CONSTANT_String_info {
u1 tag; //tag=8
u2 string_index;// 包含文字字符串的 CONSTANT_Utf8_info 表索引
}
CONSTANT_Fieldref
CONSTANT_Fieldref_info {
u1 tag; //tag=9
u2 class_index; //constant_pool 的索引,对应 CONSTANT_Class_info
u2 name_and_type_index;//constant_pool 的索引,对应 CONSTANT_NameAndType_info
}
CONSTANT_Methodref
CONSTANT_Methodref_info {
u1 tag; //tag=10
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref
CONSTANT_InterfaceMethodref_info {
u1 tag; //tag=11
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_NameAndType
CONSTANT_NameAndType_info {
u1 tag; //tag=12
u2 name_index;
u2 descriptor_index;
}
access_flags 意义如下 :
ACC_PUBLIC 0x0001
ACC_FINAL 0x0010
ACC_SUPER 0x0020
ACC_INTERFACE 0x0200
ACC_ABSTRACT 0x0400
this_class: constant_pool 中的索引值 , 指向的元素的 cp_info 等价为 CONSTANT_Class_info
CONSTANT_Class_info {
u1 tag; // 必须为 CONSTANT_Class (7)
u2 name_index; // 为指向 constant_pool 中的一个索引值
}
name_index : 指向的元素的 cp_info 等价为 CONSTANT_Utf8_info
field_info {
u2 access_flags; // 访问控制权
u2 name_index; //constant_pool 中的索引,对应于 CONSTANT_Utf8_info 描述。
u2 descriptor_index; //constant_pool 中的索引,对应于 CONSTANT_Utf8_info 描述。
u2 attributes_count;
attribute_info attributes[attributes_count]; //attribute_info 将在 mothods 后描述。
}
field_info 中 access_flages 意义如下 :
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_VOLATILE 0x0040
ACC_TRANSIENT 0x0080
其中很显然不能同时为 ACC_FINAL 和 ACC_VOLATILE ; 且前三项是互斥的。
interface 必须置 ACC_PUBLIC, ACC_STATIC,ACC_FINAL 位,且不能置其他位。
其他未指明的位保留将来使用,并且编译器应当将其置为 0 ,同时 Java 虚拟机应当忽略他们。
methods 指明了类中的所有方法。
method_info {
u2 access_flags;
u2 name_index; // 指向 constant_pool 的入口,对应为 CONSTANT_Utf8_info
u2 descriptor_index; // 指向 constant_pool 的入口,对应为 CONSTANT_Utf8_info
u2 attributes_count;
attribute_info attributes[attributes_count];
// 此处只能出现 Code 、 Exceptions 、 Synthetic 、 Deprecated 四种类型的属性
}
access_flags 访问权描述如下 :
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_SYNCHRONIZED 0x0020
ACC_NATIVE 0x0100
ACC_ABSTRACT 0x0400
ACC_STRICT 0x0800
attribute_info {
u2 attribute_name_index; //constant_pool 中的索引,对应于 CONSTANT_Utf8_info 描述。
u4 attribute_length;
u1 info[attribute_length];
}
现在已经预定义的属性有 :
1. SourceFile : attribute_info 被替代为 :
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index; // 指向 constant_pool 中的一个 CONSTANT_Utf8_info 结构。
}
2. ConstantValue : attribute_info 被替代为 :
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length; // 必须为 2
u2 constantvalue_index;
}
对于 constantvalue_index 意义如下 :
long CONSTANT_Long
float CONSTANT_Float
double CONSTANT_Double
int, short, char, byte, boolean CONSTANT_Integer
String CONSTANT_String
ConstantValue 用于 field_info 中,用于描述一个 static 常量 ,
且此时 field_info 的 access_flags 应为 ACC_STATIC
3. Code : attribute_info 被替代为 :
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack; // 执行此函数时可用的栈的最大深度
u2 max_locals; // 执行此函数可用到的最大本地变量数目,包括参数。
// 注意 : 一个 long/double 相当于 2 个变量数目 .
u4 code_length; // 本函数用到的代码长度。
u1 code[code_length]; // 实现本函数的真正字节码
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc; // 捕获违例时执行代码数组中的 [start_pc, end_pc) 部分
u2 handler_pc; // 现在还不大明白他是干嘛的 !!
u2 catch_type; // 指向 constant_pool 的索引,对应 CONSTANT_Class_info
}exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
CONSTANT_Class_info {
u1 tag; // 必须为 CONSTANT_Class (7)
u2 name_index; // 不用我再说了吧 ?
}
Code 属性用于 method_info 结构中。
4. Exceptions : attribute_info 被替代为 :
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
5. InnerClasses : attribute_info 被替代为 :
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
6. Synthetic : attribute_info 被替代为 :
Synthetic_attribute {
u2 attribute_name_index; // 不用废话了吧 ?
u4 attribute_length; // 必须为 0
}
Synthetic 用在 field_info 、 method_info 中,
一个没有出现在源程序中的变量必须使用 Synthetic 标记。
7. LineNumberTable : attribute_info 被替代为 :
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc; // 代码数组中的开始处
u2 line_number; // 源文件中的行号 ( 对于每一非空行都有这么一项 )
} line_number_table[line_number_table_length];
}
LineNumberTable 用于 Code 属性中,通常用于调试。
8. LocalVariableTable : attribute_info 被替代为 :
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length; // 当解释到代码数组的 [start_pc,start_pc+length]
// 时变量必须被赋值 ??
u2 name_index;
u2 descriptor_index;
u2 index; // 到本地变量数组的一个索引
} local_variable_table[local_variable_table_length];
}
9. Deprecated : attribute_info 被替代为 :
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length; // 必须为 0
}
当然也可以定义自己的属性,但要你自己的编译器和虚拟机实现。 JVM 将忽略自己不认可的属性。
以上是关于 Javaclass 文件的一个基本结构的分析。主要是对书上关于这一章的总结,同时参考了 : http://hi.baidu.com/52dege/blog/item/f33a3cf4092491dbf3d3854f.html 等网上资料。
看一个 java classfile 有助于我们理解的实际例子:
代码
1
:
运行结果为
:true true
代码
2
:
运行结果为
:false true
关于代码
1
和代码
2
的解释:
Java
编译器在生成
class
文件的时候对代码里面定义的字符串都会作为一个字符串常量存放在常量池中。
对于代码
1
中的
String a = "aaabbb";
和
String b = "aaabbb";
预处理在编译处理后,
a
和
b
都指向了常量池里的
”aaabbb”
,所以
a==b
是
true.
对于代码
2
中的
String b = "aaa"; b += "bbb";
编译处理后会在常量池里面生成
”aaa”
和
”bbb”,
同时,
b += "bbb";
语句会导致
Jvm
去重新创建一个
string
对象,相当于
b=new String(“aaabbb”);
自然,
aaa==bbb
是
false
。这也是为什么不推荐使用加号来拼接字符串了。
发表评论
-
Android插件式开发(一)
2012-08-30 17:45 37831.插件式开发基础 插件式开发是指,只要提供一个 ... -
使用VideoView播放rtsp视频流
2012-08-21 18:21 53591.视频播放控制 package com.exampl ... -
Log4J学习总结
2009-07-25 19:59 669Log4J 学习笔记 ... -
Java Enum 学习
2009-07-29 16:45 631Java Enum 学习 1. ... -
Java Annotation 浅析
2009-08-16 16:33 796Java Annotation 浅析 ... -
Java ThreadLocal使用浅析
2009-08-18 20:14 758Java ThreadLocal使用 ... -
Java 线程池ThreadPoolExecutor
2009-09-01 13:12 742Java 线程池 ThreadP ... -
DbUnit 简介和使用 (puts your database into a known state)
2009-12-16 17:06 726DbUnit 简介 1. ... -
Java反射之Method调用和Filed设置
2010-01-24 14:13 698反射是java的一个高级特 ... -
java float double精度为什么会丢失?浅谈java的浮点数精度问题
2010-02-27 21:46 787由于对float或double 的使用不当,可能会出现精度丢 ... -
Java反射之JDK动态代理实现简单AOP
2010-04-04 13:52 500JDK动态代理实现简单AOP ... -
java字符编码原理浅析
2010-05-09 15:10 340本周遇到一个java乱码问题,于是对java的编码问题做 ... -
java字符编码原理浅析
2010-05-09 15:10 661本周遇到一个java乱码问题,于是对java的编码问题做 ... -
Eclipse RCP中使用Swing组件(转载)
2012-01-30 20:16 962http://twaver.servasoft.com/?ta ...
相关推荐
另外,` jclasslib`是一款可视化的字节码查看器,它提供了更直观的方式查看和分析.class文件,包括类结构、常量池、字段和方法的详细信息。使用这样的工具可以帮助我们更好地理解JVM的内部工作原理。 此外,学习...
Java Class文件编辑器,如JD-GUI 0.3.3 绿色版,是一种用于查看和理解Java字节码的工具,对于开发者而言尤其重要,因为它提供了将已编译的`.class`文件反编译回源代码的能力。在深入讨论这个工具之前,我们先来了解...
总的来说,使用C#解析Java的class文件是一项挑战性的任务,它需要对Java字节码格式有深入理解,并熟练掌握C#的IO和数据结构处理。通过这样的实践,开发者不仅可以提升自己的跨语言编程技能,还能增进对Java字节码和...
标题提到的"java class文件反编译工具"主要指的是一类能够解析和解释Java字节码的软件。在Java平台上,源代码被编译成字节码,这是一种中间语言,可以在任何支持Java虚拟机(JVM)的设备上运行。然而,字节码是机器...
在IT领域,反编译是一种将已编译的字节码(如Java的.class文件)转换回源代码(如Java的.java文件)的过程。标题提到的"反编译软件"是一种工具,它允许用户查看和理解Java类文件的内部结构,即使原始的源代码不再...
Java Class文件是Java程序在编译后生成的字节码文件,它包含了程序的结构和指令,用于JVM(Java虚拟机)执行。反编译工具则是将这些字节码转换回可读的源代码,帮助开发者理解已编译的程序逻辑,进行代码调试、学习...
Java类文件(.class)是Java源代码经过编译后的二进制文件,它包含了机器码,用于JVM(Java虚拟机)执行。反编译是将这些二进制.class文件转换回接近原始的Java源代码(.java文件)的过程。这个过程对于理解已编译...
JavaClass反编辑器是一款专门用于分析和理解Java字节码的工具,它允许开发者查看、解构和理解编译后的Java类文件。在Java应用程序的开发、调试和逆向工程中,这类工具扮演了重要角色。Java类文件是Java源代码经过...
今天我们将探讨一款名为"class文件查看器"的工具,它是一个跨平台的实用程序,专为查看和分析Java class文件而设计。通过这个工具,开发者能够直观地查看class文件中的指令以及16进制字节码表示,极大地增强了代码...
总的来说,JAVA-class编辑器是Java开发者的重要工具之一,它提供了一种途径去探索、理解和修改Java字节码,从而提升开发效率,优化程序性能,并进行深度学习。了解和掌握这类工具的使用,对于提升开发者的技术水平和...
JavaClassViewer是一款专为开发者设计的工具,用于查看和理解`.class`文件的内部结构。`.class`文件是Java编译后的二进制文件,它包含了程序的字节码,这是Java虚拟机(JVM)运行的基础。通过使用JavaClassViewer,...
1. **Java编译过程**:当开发者编写完.java文件后,javac编译器会进行词法分析、语法分析、语义分析等步骤,将高级语言转化为机器可以理解的字节码指令,这些指令存储在.class文件中。每个类都对应一个.class文件,...
Java字节码操作库BCEL(Byte Code Engineering Library)是一个强大的工具,用于分析、修改和创建Java类文件。它是Apache软件基金会的Jakarta项目的一部分,为开发者提供了对字节码的底层控制,使得开发者能够在运行...
### Java中的序列化与反序列化详解 #### 一、概念理解 ...通过上述分析,我们可以看到Java中的序列化与反序列化机制是非常实用且强大的。掌握这些技术可以帮助开发者更好地处理对象的存储与传输问题。
例如,`ObjectSaver.java`文件可能包含一个实现了序列化的类定义: ```java public class MySerializableObject implements Serializable { private String name; private int age; // 构造器,getter和setter...
Java虚拟机(JVM)是一种能够执行字节码(.class文件)的虚拟机。它是Java平台的核心部分之一,使得Java应用程序可以在任何支持JVM的平台上运行,而无需考虑底层操作系统的差异性。JVM的主要职责包括: - **加载代码...
3. **远程方法调用(RMI)**:在分布式计算环境中,序列化允许对象跨越网络边界,实现在不同机器间的对象交换,是RMI的基础技术之一。 #### 序列化的过程剖析 序列化过程中,对象的实例变量及其值被转换为可存储或...
1. **编译与解释**:Java代码首先需要通过JDK(Java Development Kit)中的javac编译器转化为字节码(.class文件),然后由Java虚拟机(JVM)执行。了解这个过程有助于优化代码性能和理解异常处理。 2. **面向对象...