`
爪哇岛岛主
  • 浏览: 37803 次
  • 性别: Icon_minigender_1
  • 来自: 杭州(也就是天堂)
社区版块
存档分类
最新评论

浅析class文件内部结构

阅读更多
      最近在为工作的事情搞的很是纠结。由于前段时间在iteye上发表了一篇“应届生,求内推”的帖子,也联系了几个“内推手”。虽然后来不成功,不过还是要感谢大部分人。究其原因可能是因为我人在南昌,看到简历后觉得离工作的地方太远,所以没有发面试通知把。不过找工作是找工作,学习还是不能忘记的。下面的这篇文章,是我这几天看《深入浅出java 虚拟机》第六章 总结出来的一些自己的东西。
      我在这里主要讲的是class file 文件结构。首先要给出两张表,第一张是class文件基本类型,第二张是class文件格式。
表6-1 class文件“基本类型”
u1 1个字节,无符号类型
u2 2个字节,无符号类型
u4 4个字节,无符号类型
u8 8个字节,无符号类型


表6-2 classfile表的格式
类型 名称 数量
U4 Magic 1
U2 Minor_version 1
U2 Major_version 1
U2 Constant_pool_count 1
Cp_info Constant_pool Constant_pool_count-1
U2 Access_flags 1
U2 This_class 1
U2 Super_class 1
U2 Interfaces_count 1
U2 Interfaces Interfaces_count
U2 Fields_count 1
Field_info Fields Fields_count
U2 Methods_count 1
Method_info Methods Methods_count
U2 Attributes_count 1
Attribute_info Attributes Attributes_count
对于这个表的格式,我不想全部翻译其意义,就前面几个字段的意义做一下简要说明就行了,后面的都可以“观其字面意思,就可知其内部含义”。
(1)magic(魔数)
每一个java class文件的前4个字节被称为它的魔数(magic number):0XCAFEBABE。魔数的作用在于,可以轻松地分辨出java class文件和非java class文件。如果一个文件不是以0xCAFEBABE开头。那它就肯定不是java class文件。文件格式定义者能够自由选择魔数,前提是这个选定的魔数值没有被广泛应用。当java还被称为“Oak”的时候,这个魔数就已经定下来了。一招Patrick Naughton(最初java开发小组的关键成员)的说法:“早在java第一次作为该语言的名字发布以前,我们就在寻找一些好玩的、唯一的、容易记忆的东西。选择0xCAFEBABE只不过是一个巧合,它象征着著名咖啡品牌Peet’s Coffee中深受欢迎的baristas(一种咖啡名称)。它预示了java这个名字的出现”。
(2)minor_version和major_version
Class文件的下面4个字节包含了主、次版本号。随着java技术的发展,java class文件格式可能会加入新特性。Class文件格式一旦发生变化,版本号也会随之变化。对于java虚拟机来说,版本号确定了特定的class文件格式,通常只有给定主版本号和一系列次版本号后,java虚拟机才能够读取class文件。如果class文件的版本号超出了java虚拟机所能处理的有效范围,java虚拟机将不会处理该class文件。
在sun的jdk1.0.2发布版中,java虚拟机实现支持从45.0(主版本号为45,次版本号为0)到45.3的class文件格式。在所有jdk1.1发布版中的虚拟机都能够支持版本从45.0到45.65535的class文件格式。在sun的1.2版本的sdk中,虚拟机能够支持从版本45.0到46.0的class文件格式。
1.0或1.2版本的编译器能够产生版本号为45.3的class文件。在sun的1.2版本sdk中,javac编译器默认产生版本号为45.3的class文件。但如果在javac命令行中指定了-target1.2标志,1.2版本的编译器将产生版本号为46.0的class文件。1.0或1.1版本的虚拟机上不能运行使用-target1.2标志所产生的class文件。
Java虚拟机实现的第二版中修改了对class文件主版本号和次版本号的解释。对于第二版而言,class文件的主版本号与java平台主发布版的版本号保持一致(例如:在java2平台发布版上,主版本号从45到46),次版本号与特定主平台发布版的各个发布版相关。因此,尽管不同的class文件格式可以由不同的版本号表示,但版本号不一样并不代表class文件格式不同。版本号不同的原因可能只是因为class文件由不同发布版本的java平台产生,可能class文件的格式并没有改变。
(3)constant_pool_count和constant_pool
在class文件中,魔数和版本号后面的是常量池。正如第五章中所述,常量池包含了与文件中类和接口相关的常量。常量池中存储了注入文字字符串、final变量值、类名和方法名的常量。Java虚拟机把常量池组织为入口列表的形式。在实际列表constant_pool之前,是入口在列表中的计数constant_pool_count。
(4)access_flags
紧接常量池后的两个字节称为access_flags,它展示了文件中定义的类或接口的几段信息。例如,访问标志指明文件中定义的是类还是接口;访问标志还定义了在类或接口的声明中,使用了哪种修饰符;类和接口是抽象的,还是公共的;类的类型可以为final,而final类不可能是抽象的;接口不能为final类型。

下面我根据一个实例来简要剖析class文件结构
首先,新建一个java源文件,并且编译出class文件。这个事用来做实验的,随便一点就OK了。

类名称:MyTest.java
package app;

/**
 * <p>
 *  这是一个测试源文件,用来生成class文件,分析class文件结构
 * </p>
 * @author 杨
 *
 */
public class MyTest {

	/**
	 * 属性列表
	 */
	private Integer id;
	private String name;
	
	/**
	 * 构造器
	 */
	public MyTest(){
		this.id = 0;
		this.name = "";
	};
	
	/**
	 * 重载构造函数
	 */
	public MyTest(Integer id,String name){
		this.id = id;
		this.name = name;
	}

	/**
	 *属性存取方法
	 */
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
}


编译后的MyTest.class文件内容如下(以文本方式打开):
漱壕   1 )  
app/MyTest  java/lang/Object id Ljava/lang/Integer; name Ljava/lang/String; <init> ()V Code
  
 	 

    java/lang/Integer   valueOf (I)Ljava/lang/Integer;	       	     LineNumberTable LocalVariableTable this Lapp/MyTest; ((Ljava/lang/Integer;Ljava/lang/String;)V getId ()Ljava/lang/Integer; setId (Ljava/lang/Integer;)V getName ()Ljava/lang/String; setName (Ljava/lang/String;)V 
SourceFile MyTest.java !                  	 
     I     * *  *                                	      Y     * *+ *,               	                                      /     *            &              ! "     >     *+        
    *  +                    # $     /     *            .              % &     >     *+        
    2  3                    '    (


其实从上面的class文件中也可以看出一点端倪出来(尽管是乱码居多)。

我们现在分析一下class文件结构对应于上面给出那张表,每个项在这个文件中所指示的具体的值。当然了,这种乱码打开的肯定不适合分析,那就以16进制方式打开把。

CA FE BA BE 00 00 00 31  00 29 07 00 02 01 00 0A
61 70 70 2F 4D 79 54 65  73 74 07 00 04 01 00 10
6A 61 76 61 2F 6C 61 6E  67 2F 4F 62 6A 65 63 74
01 00 02 69 64 01 00 13  4C 6A 61 76 61 2F 6C 61
6E 67 2F 49 6E 74 65 67  65 72 3B 01 00 04 6E 61
6D 65 01 00 12 4C 6A 61  76 61 2F 6C 61 6E 67 2F
53 74 72 69 6E 67 3B 01  00 06 3C 69 6E 69 74 3E
01 00 03 28 29 56 01 00  04 43 6F 64 65 0A 00 03
00 0D 0C 00 09 00 0A 0A  00 0F 00 11 07 00 10 01
00 11 6A 61 76 61 2F 6C  61 6E 67 2F 49 6E 74 65
67 65 72 0C 00 12 00 13  01 00 07 76 61 6C 75 65
4F 66 01 00 16 28 49 29  4C 6A 61 76 61 2F 6C 61
6E 67 2F 49 6E 74 65 67  65 72 3B 09 00 01 00 15
0C 00 05 00 06 08 00 17  01 00 00 09 00 01 00 19
0C 00 07 00 08 01 00 0F  4C 69 6E 65 4E 75 6D 62
65 72 54 61 62 6C 65 01  00 12 4C 6F 63 61 6C 56
61 72 69 61 62 6C 65 54  61 62 6C 65 01 00 04 74
68 69 73 01 00 0C 4C 61  70 70 2F 4D 79 54 65 73
74 3B 01 00 28 28 4C 6A  61 76 61 2F 6C 61 6E 67
2F 49 6E 74 65 67 65 72  3B 4C 6A 61 76 61 2F 6C
61 6E 67 2F 53 74 72 69  6E 67 3B 29 56 01 00 05
67 65 74 49 64 01 00 15  28 29 4C 6A 61 76 61 2F
6C 61 6E 67 2F 49 6E 74  65 67 65 72 3B 01 00 05
73 65 74 49 64 01 00 16  28 4C 6A 61 76 61 2F 6C
61 6E 67 2F 49 6E 74 65  67 65 72 3B 29 56 01 00
07 67 65 74 4E 61 6D 65  01 00 14 28 29 4C 6A 61
76 61 2F 6C 61 6E 67 2F  53 74 72 69 6E 67 3B 01
00 07 73 65 74 4E 61 6D  65 01 00 15 28 4C 6A 61
76 61 2F 6C 61 6E 67 2F  53 74 72 69 6E 67 3B 29
56 01 00 0A 53 6F 75 72  63 65 46 69 6C 65 01 00
0B 4D 79 54 65 73 74 2E  6A 61 76 61 00 21 00 01



分析:
项目 所占位数 说明
Magic(魔数) 4 CA FE BA BE 符合class文件格式
Minor_version(次版本号) 2 00 00 0
Major_version(主版本号) 2 00 31  十进制是49(JDK1.6)
Constant_pool_count(常量池数) 2 00 29 41个
Constant_pool 不定(cp_info) 后面一大串


心情不好,休息。下个礼拜可能去上海找工作。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics