Class文件(含实例)

2 篇文章 0 订阅

最近在温习深入理解Java虚拟机,梳理一下~~~~欢迎大家批评指正啊哈

引言

Java著名的 “Write Once,Run Anywhere” --"与平台无关"的理想,最终实现在操作系统的应用层上.
Sun公司以及其他虚拟机提供商发布了许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而得以实现这个冲破平台界限的理想.

基石

ByteCode—字节码,是构成平台无关性的基石,即使现在语言无关性越来越得到开发者重视,其他语言也可以运行在Java虚拟机上.但实现语言无关性的基础仍然是虚拟机字节码存储格式 .Java虚拟机不和包括Java在内的任何语言绑定,只与"Class文件"–特定的二进制文件格式相关联.例如:

  1. java程序(*.java)使用javac编译器可以将程序代码编译成Class文件
  2. JRuby程序(*.rb)使用jrubyc编译器也可以将程序代码编译成Class文件
  3. Groovy程序(*.groovy)使用groovyc编译器可以将程序代码编译成Class文件
  4. 其他语言程序使用对应的编译器可以将程序代码编译成Class文件

所以说虚拟机并不关心Class的来源是何种语言,未来可能也许maybe Java在语言无关性上会超越它的平台无关性也不可知呢

Class类文件的结构

根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数.

  1. 无符号数
    无符号数属于基本的数据类型,以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节和8个字节的无符号数。
    用来描述数字、索引引用、数量值或者按照UTF-8构成字符串值。

  2. 由多个无符号数或者其他表作为数据项构成的复合数据类型。所有表都习惯的以"_info"结尾。
    用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一张表。

class文件格式

名称数量
u4magic1
u2minor_version1
u2major_version1
u2constant_pool_count1
cp_infoconstant_poolconstant_pool_count-1
u2access_flags1
u2this_class1
u2super_class1
u2interfaces_count1
u2interfacesinterfaces_count
u2fields_count1
field_infofieldsfields_count
u2methods_count1
methods_infomethodsmethods_count
u2attributes_count1
attribute_infoattributesattribute_count

各字段解释

1.魔数

每一个class文件的头4个字节称为魔数,它唯一的作用是确定这个文件是否为一个能被虚拟机接受的Class文件。非常多文件存储标准中都使用魔数来进行身份识别。譬如图片格式gif、jpeg等。使用魔数而不是拓展名来进行识别主要是基于安全方面的考虑,由于文件拓展格式能够任意修改。

Class文件的魔数为:0xCAFEBABE(咖啡宝贝?)。这个魔数似乎也预示着日后JAVA这个商标名称的出现。

2.版本

第五六个字节是次版本(Minor Version)。第7和第8个字节是主版本(Major Version)。
高版本号的JDK能够向下兼容曾经版本号的Class文件,可是无法执行以后版本号的Class文件,即使文件格式并未发生变化,虚拟机也必须拒绝执行超过其版本号号的Class文件。

3.常量池

常量池中主要存放两大类常量:字面量符号引用。字面量如文本字符串、声明为final的常量值等。符号引用包含三类常量:类和接口的全限定名、字段的名称和描写叙述符、方法的名称和描写叙述符。

4.访问标志

在常量池结束之后,紧接着的两个字节代表访问标志。用于识别一些类或者接口层次的访问信息。
例如 0x0021= 0x0001 | 0x0020 =ACC_PUBLIC | ACC_SUPER

5.类索引、父类索引和接口索引集合

由这3项数据来确定这个类的继承关系
this_class:类索引,用于确定这个类的全限定名,占2字节
super_class:父类索引。用于确定这个类父类的全限定名(Java语言不同意多重继承,故父类索引仅仅有一个
除了java.lang.Object类之外全部类都有父类,故除了java.lang.Object类之外,全部类该字段值都不为0),占2字节
interfaces_count:接口索引计数器。占2字节。
假设该类没有实现不论什么接口。则该计数器值为0,而且后面的接口的索引集合将不占用不论什么字节。
interfaces:接口索引集合,一组u2类型数据的集合。用来描写叙述这个类实现了哪些接口。这些被实现的接口将按implements语句(假设该类本身为接口,则为extends语句)后的接口顺序从左至右排列在接口的索引集合中

6.字段表集合

字段表用于描写叙述接口或者类中声明的变量,包含类级变量实例级变量(是否是static)。但不包含在方法内部声明的局部变量。

字段作用域(public、protected、private修饰符)、是类级别变量还是实例级别变量(static修饰符)、可变性(final修饰符)、并发可见性(volatile修饰符)、可序列化与否(transient修饰符)、字段数据类型(基本类型、对象、数组)以及字段名称。

7.方法表集合

#TODO

8.属性表集合

#TODO

实例

HexTest.java文件

package com.cx.action;

public class HexTest {
    public void code(){
        System.out.println("hello hex");
        System.out.println("alalalaallalaalallalalla");
        int i = 0;
        for(; i < 2; i++){
            System.out.println("testing:"+ i );
        }
    }

}

查看class文件

myb@myb-OptiPlex-7040:~/IdeaProjects/TestPlugin/src/com/cx/action$ javap -verbose HexTest.class

HexTest.class

cafe babe 0000 0034 002f 0a00 0d00 1609
0017 0018 0800 190a 001a 001b 0800 1c07
001d 0a00 0600 1608 001e 0a00 0600 1f0a
0006 0020 0a00 0600 2107 0022 0700 2301
0006 3c69 6e69 743e 0100 0328 2956 0100
0443 6f64 6501 000f 4c69 6e65 4e75 6d62
6572 5461 626c 6501 0004 636f 6465 0100
0d53 7461 636b 4d61 7054 6162 6c65 0100
0a53 6f75 7263 6546 696c 6501 000c 4865
7854 6573 742e 6a61 7661 0c00 0e00 0f07
0024 0c00 2500 2601 0009 6865 6c6c 6f20
6865 7807 0027 0c00 2800 2901 0018 616c
616c 616c 6161 6c6c 616c 6161 6c61 6c6c
616c 616c 6c61 0100 176a 6176 612f 6c61
6e67 2f53 7472 696e 6742 7569 6c64 6572
0100 0874 6573 7469 6e67 3a0c 002a 002b
0c00 2a00 2c0c 002d 002e 0100 1f63 6f6d
2f63 782f 746f 6e67 6675 6475 6e2f 6163
7469 6f6e 2f48 6578 5465 7374 0100 106a
6176 612f 6c61 6e67 2f4f 626a 6563 7401
0010 6a61 7661 2f6c 616e 672f 5379 7374
656d 0100 036f 7574 0100 154c 6a61 7661
2f69 6f2f 5072 696e 7453 7472 6561 6d3b
0100 136a 6176 612f 696f 2f50 7269 6e74
5374 7265 616d 0100 0770 7269 6e74 6c6e
0100 1528 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 2956 0100 0661 7070 656e
6401 002d 284c 6a61 7661 2f6c 616e 672f
5374 7269 6e67 3b29 4c6a 6176 612f 6c61
6e67 2f53 7472 696e 6742 7569 6c64 6572
3b01 001c 2849 294c 6a61 7661 2f6c 616e
672f 5374 7269 6e67 4275 696c 6465 723b
0100 0874 6f53 7472 696e 6701 0014 2829
4c6a 6176 612f 6c61 6e67 2f53 7472 696e
673b 0021 000c 000d 0000 0000 0002 0001
000e 000f 0001 0010 0000 001d 0001 0001
0000 0005 2ab7 0001 b100 0000 0100 1100
0000 0600 0100 0000 0300 0100 1200 0f00
0100 1000 0000 7400 0300 0200 0000 37b2
0002 1203 b600 04b2 0002 1205 b600 0403
3c1b 05a2 0022 b200 02bb 0006 59b7 0007
1208 b600 091b b600 0ab6 000b b600 0484
0101 a7ff dfb1 0000 0002 0011 0000 001e
0007 0000 0005 0008 0006 0010 0007 0012
0008 0017 0009 0030 0008 0036 000b 0013
0000 0007 0002 fc00 1201 2300 0100 1400
0000 0200 15

用javap 命令可以查看其翻译后的结果

myb@myb-OptiPlex-7040:~/IdeaProjects/TestPlugin/src/com/cx/action$ javap -verbose HexTest.class

翻译结果

Classfile /home/myb/IdeaProjects/TestPlugin/src/com/cx/action/HexTest.class
  Last modified 2019-1-23; size 741 bytes
  MD5 checksum a946e36d791e2c5777c7f84078546b6f
  Compiled from "HexTest.java"
public class com.cx.action.HexTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #13.#22        // java/lang/Object."<init>":()V
   #2 = Fieldref           #23.#24        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #25            // hello hex
   #4 = Methodref          #26.#27        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = String             #28            // alalalaallalaalallalalla
   #6 = Class              #29            // java/lang/StringBuilder
   #7 = Methodref          #6.#22         // java/lang/StringBuilder."<init>":()V
   #8 = String             #30            // testing:
   #9 = Methodref          #6.#31         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #10 = Methodref          #6.#32         // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  #11 = Methodref          #6.#33         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #12 = Class              #34            // com/cx/action/HexTest
  #13 = Class              #35            // java/lang/Object
  #14 = Utf8               <init>
  #15 = Utf8               ()V
  #16 = Utf8               Code
  #17 = Utf8               LineNumberTable
  #18 = Utf8               code
  #19 = Utf8               StackMapTable
  #20 = Utf8               SourceFile
  #21 = Utf8               HexTest.java
  #22 = NameAndType        #14:#15        // "<init>":()V
  #23 = Class              #36            // java/lang/System
  #24 = NameAndType        #37:#38        // out:Ljava/io/PrintStream;
  #25 = Utf8               hello hex
  #26 = Class              #39            // java/io/PrintStream
  #27 = NameAndType        #40:#41        // println:(Ljava/lang/String;)V
  #28 = Utf8               alalalaallalaalallalalla
  #29 = Utf8               java/lang/StringBuilder
  #30 = Utf8               testing:
  #31 = NameAndType        #42:#43        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #32 = NameAndType        #42:#44        // append:(I)Ljava/lang/StringBuilder;
  #33 = NameAndType        #45:#46        // toString:()Ljava/lang/String;
  #34 = Utf8               com/cx/action/HexTest
  #35 = Utf8               java/lang/Object
  #36 = Utf8               java/lang/System
  #37 = Utf8               out
  #38 = Utf8               Ljava/io/PrintStream;
  #39 = Utf8               java/io/PrintStream
  #40 = Utf8               println
  #41 = Utf8               (Ljava/lang/String;)V
  #42 = Utf8               append
  #43 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #44 = Utf8               (I)Ljava/lang/StringBuilder;
  #45 = Utf8               toString
  #46 = Utf8               ()Ljava/lang/String;
{
  public com.cx.action.HexTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1          
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public void code();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String hello hex
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: ldc           #5                  // String alalalaallalaalallalalla
        13: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        16: iconst_0
        17: istore_1
        18: iload_1
        19: iconst_2
        20: if_icmpge     54
        23: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        26: new           #6                  // class java/lang/StringBuilder
        29: dup
        30: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
        33: ldc           #8                  // String testing:
        35: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        38: iload_1
        39: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        42: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        45: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        48: iinc          1, 1
        51: goto          18
        54: return
      LineNumberTable:
        line 5: 0
        line 6: 8
        line 7: 16
        line 8: 18
        line 9: 23
        line 8: 48
        line 11: 54
      StackMapTable: number_of_entries = 2
        frame_type = 252 /* append */
          offset_delta = 18
          locals = [ int ]
        frame_type = 35 /* same */
}
SourceFile: "HexTest.java"

以下与本文无关,同时希望大家批评指正
————————————————————————————————————————————————————————
其中这一句

Code:
      stack=1, locals=1, args_size=1          

在任何实例方法里,都可以通过this关键字访问此方法所属的对象,这个访问机制的实现是通过Javac编译器编译时,把对this关键字的访问转变为对一个普通方法参数的访问,然后在虚拟机调用实例方法的时候自动传入此参数。因此实例方法的局部变量表至少会存在一个指向当前对象实例的局部变量,局部变量表中也会预留出第一个slot位来存放实例对象的引用。这个处理只对实例方法有效,声明为static则args_size 就为0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值