Java字节码初识

285 阅读3分钟

前言

众所周知,Java字节码技术造就Java “一次部署,处处运行”的伟大理想,Java使用了一个自定义的中间语言,不基于操作系统的底层接口,而是基于自己的VM虚拟机,把对接系统底层操作交给VM虚拟机来处理,Java的开发者无需关心这些,即使想关心,也可使用Java提供的对应的工具类或者参数配置。那么字节码是什么呢?

概念

维基百科中是这样定义的:Java 字节码(英语:Java bytecode)是Java虚拟机执行的一种指令格式。大多数操作码都是一个字节长,而有些操作需要参数,导致了有一些多字节的操作码。而且并不是所有可能的256个操作码都被使用;其中有51个操作码被保留做将来使用。除此之外,原始Java平台开发商,太阳微系统,额外保留了3个代码永久不使用。

实战

首先,定义一个简单的基础类。如下:

public class SimpleAddDemo {

    public static void main(String[] args) {
        int a = 28;
        int b = 2;
        for (int i=0; i<7; ++i) {
            if (i % 2 == 0) {
                a++;
                b++;
            }
        }
        long c = (a + b) * 5;
    }
}

以上为一个简单的数字逻辑操作,接下来,使用javac将其进行编译。再使用javap -c进行反编译class文件,得到以下的字节码信息

public class com.jackpan.jvm.basic.SimpleAddDemo {
  public com.jackpan.jvm.basic.SimpleAddDemo();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        28
       2: istore_1
       3: iconst_2
       4: istore_2
       5: iconst_0
       6: istore_3
       7: iload_3
       8: bipush        7
      10: if_icmpge     31
      13: iload_3
      14: iconst_2
      15: irem
      16: ifne          25
      19: iinc          1, 1
      22: iinc          2, 1
      25: iinc          3, 1
      28: goto          7
      31: iload_1
      32: iload_2
      33: iadd
      34: iconst_5
      35: imul
      36: i2l
      37: lstore_3
      38: return
}

只需关注main方法的Code部分,以下对这几个指令进行解释:
bipush 28 当int的值在-128~127中,JVM 采用 bipush 指令将常量压入栈中
istore_1 将栈顶 int 型数值存入第二个本地变量
iconst_2 将int值2压入栈中,当 int 取值 -1~5 时,JVM 采用 iconst 指令将常量压入栈中。 iload_3 将第四个 int 型本地变量推送至栈顶
if_icmpge 30 比较栈顶两 int 型数值的大小,当结果大于或等于 0 时跳转至30行
irem 将栈顶两 int 型数值作取模运算并将结果压入栈顶
ifne 25 当栈顶 int 型数值不等于 0 时跳转25行
iinc 将栈顶 int 型变量增加指定值
goto 7 无条件跳转7行
iadd 将栈顶两 int 型数值相加并将结果压入栈顶
imul 将栈顶两 int 型数值相乘并将结果压入栈顶 i2l 将栈顶 int 型数值强制转成 long 型数值并将结果压入栈顶
return 从当前方法返回 void

总结

以上的13个命令包含了大多数的数值操作,很多命令都是一两个字母的变化而来的,可以根据一个命令扩展对应的多个命令。

引用

Java字节码-维基百科
官方JVM 字节码文档