Java字节码笔记

Java字节码 .class文件

   Java语言的write once run anywhere能够得以实现其中重要的部分就是关于其字节码的生成,Java虚拟机JVM通过将字节码文件解析到各种不同的平台对应的机器语言来实现了其跨平台的特性。那么如何才能看到字节码,又如何来读懂它呢。
   关于.class文件,其实还有很多其他的语言也是基于这一特点的,例如Scala、groovy、kotlin等,都是基于jvm这一平台,通过相应的编译器生成了.class文件。下面给一个简单地例子:

public class ClassTest {

    private int a;

    public void print() {
        System.out.println(this.a);
    }
}

使用javac 文件名.java对其进行编译得到.class文件

本文先使用notepad++ 直接查看其字节码文件,需要先安装HEX-Editor插件

插件管理

安装后notepad++会重启,然后选择使用view in HEX来查看.class文件

hex-editor

16bit查看效果

“真好看”

Class文件格式(u1、u2、u4、u8表示字节长度(1,2,4,8))
类型名称数量
u4magic1
u2minor_version1
u2major_version

1

u2constant_pool_count1
cp_infoconstant_pool

constant_pool_count-1

u2access_flags1
u2this_class1
u2super_class1
u2interfaces_count1
u2interfacesinterfaces_count
u2fields_count1
field_infofieldsfields_count
u2methods_count1
method_infomethodsmethods_count
u2attributes_count1
attribute_infoattributesattributes_count

开头的cafe babe可以看成是一种文件的前缀,通过和这个标识才可以被jvm接受。

紧接着的00 00 00 34表示52(10),java版本号从45开始,JDK1.0-1.1--(45.0~45.3) 1.2--46 1.3--47 1.4--48 1.5--49 1.6--50 1.7--51 1.8--52

这样来看字节码好像也得不到什么其他有效的信息了,因此可以通过使用javap命令来反编译字节码文件

使用命令javap -v -p ClassTest.class

// 描述.class文件所在位置
Classfile /D:/IdeaWorkspace/XXXXX/XXXXXX/src/main/java/com/XXXX/XXXX/ClassTest.class
  // 字面含义
  Last modified 2019-8-8; size 413 bytes
  MD5 checksum df5d2b60f97b3930a43c8a375b00340a
  Compiled from "ClassTest.java"
public class com.XXXX.XXXX.ClassTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#16         // java/lang/Object."<init>":()V
   #2 = Fieldref           #17.#18        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Fieldref           #5.#19         // com/XXXX/XXXX/ClassTest.a:I
   #4 = Methodref          #20.#21        // java/io/PrintStream.println:(I)V
   #5 = Class              #22            // com/XXXX/XXXX/ClassTest
   #6 = Class              #23            // java/lang/Object
   #7 = Utf8               a
   #8 = Utf8               I
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               print
  #14 = Utf8               SourceFile
  #15 = Utf8               ClassTest.java
  #16 = NameAndType        #9:#10         // "<init>":()V
  #17 = Class              #24            // java/lang/System
  #18 = NameAndType        #25:#26        // out:Ljava/io/PrintStream;
  #19 = NameAndType        #7:#8          // a:I
  #20 = Class              #27            // java/io/PrintStream
  #21 = NameAndType        #28:#29        // println:(I)V
  #22 = Utf8               com/XXXX/XXXX/ClassTest
  #23 = Utf8               java/lang/Object
  #24 = Utf8               java/lang/System
  #25 = Utf8               out
  #26 = Utf8               Ljava/io/PrintStream;
  #27 = Utf8               java/io/PrintStream
  #28 = Utf8               println
  #29 = Utf8               (I)V
{
  private int a;
    descriptor: I
    flags: ACC_PRIVATE

  public com.XXXX.XXXX.ClassTest();
    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 print();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: aload_0
         4: getfield      #3                  // Field a:I
         7: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        10: return
      LineNumberTable:
        line 8: 0
        line 9: 10
}
SourceFile: "ClassTest.java"

内容、关键字:

flags(access_flags):ACC_PUBLIC, ACC_SUPER 表示的是类的访问标志,这个访问标志用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类,是否被声明为final类型

标志名标志值含义
ACC_PUBLIC0x0001

是否为public类型

ACC_FINAL

0x0010是否为final类型,只有类可以设置
ACC_SUPER0x0020

是否允许使用invokespecial字节码指令的新语义.

ACC_INTERFACE0x0200标志这是一个接口
ACC_ABSTRACT0x0400是否为abstract类型,对于接口或者抽象类来说,
次标志值为真,其他类型为假
ACC_SYNTHETIC0x1000标志这个类并非由用户代码产生
ACC_ANNOTATION0x2000标志这是一个注解
ACC_ENUM 0x4000标志这是一个枚举
 其中的invokespecial为jvm指令
 
指令说明
invokevirtual用于调用对象的实例方法,根据对象的实际类型进行分派
invokeinterface用于调用接口方法,会在运行时搜索一个实现了这个接口方法的对象,找出合适的方法进行调用
invokespecial用于调用一些需要特殊处理的实例方法,包括初始化方法、私有方法、父类方法
invokestatic用于调用类方法
invokedynamic用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值