ZB-056-05JVM字节码

字节码(IR 中间表示)

字节码——平台无关的基石

  • 基于栈(操作数栈)的、与平台无关的计算模型
  • 可以由多种方式生成
    • JVM上的编程语言
    • 直接生成字节码

JVM如何实现平台无关性?

  • JVM中所有代码,都是自己定义的一套字节码流程
  • 它的字节码中你没有看到任何和操作系统有关的指令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    // class version 49.0 (49)
    // access flags 0x21
    public class Main {

    // compiled from: Main.java

    // access flags 0x1
    public <init>()V
    L0
    LINENUMBER 1 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
    L1
    LOCALVARIABLE this LMain; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

    // access flags 0x9
    public static main([Ljava/lang/String;)V
    L0
    LINENUMBER 3 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ICONST_5
    INVOKESTATIC Main.f (I)I
    INVOKEVIRTUAL java/io/PrintStream.println (I)V
    L1
    LINENUMBER 4 L1
    RETURN
    L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

    // access flags 0x9
    public static f(I)I
    L0
    LINENUMBER 7 L0
    ILOAD 0
    ICONST_2
    IF_ICMPGE L1
    L2
    LINENUMBER 8 L2
    ICONST_1
    IRETURN
    L1
    LINENUMBER 10 L1
    ILOAD 0
    ILOAD 0
    ICONST_1
    ISUB
    INVOKESTATIC Main.f (I)I
    IADD
    IRETURN
    L3
    LOCALVARIABLE n I L0 L3 0
    MAXSTACK = 3
    MAXLOCALS = 1
    }
  • 它在运行时和任何东西都没关。这也是它能跨平台的基石

    • 它的基石就是 字节码,一种中间表示
  • 它的所有操作都是在栈上完成的
  • JVM满脑子都是 上面那样的字节码,它不管什么 java / ruby / groovy ,只执行字节码

如何生成java识别的字节码呢?

  • java包含两种规范 JLS 和 JVMS
  • JVM只执行 字节码那一坨东西,而java语言和他没任何关系。它们之间的联系是 java编译器
    • 也就是说从 源代码(人类能看懂) 到 JVM能识别的字节码的过程 需要经过编译器

为什么Java设计的时候要把 JLS / JVMS 分开

  • 为了未来允许其他语言生成 字节码,因为JVM只认识 字节码
  • java有意的将它们分开使得你可以在 JVM上执行不同的语言 ruby/ groovy

还有一种直接生成字节码

  • 如果你有兴趣,请打开你的 Main.class文件,你需要一个特殊的工具去查看字节码的东西。如16进制编辑器。
  • 打开后你会发现,它会以字节的方式定义了一组非常紧凑的模型,我们称之为字节码。它的基本单元是一个一个的字节。那它和源代码的区别呢?
    • 人类能读懂的我们称之为 字符文件
    • 机器能读懂的我们称之为 字节码
    • 其中最重要的字节码标识是 Magic number) ,你看到java的 magic number 是 CAFEBABE。几乎所有的文件都有 magic number,用来标识是什么文件

java自带的工具

  • javap Main查看类信息 或者 javap -v Main 查看更多信息
  • 如果你喜欢图形化工具可以搜 classpy
  • idea插件 bytecode

如果你不嫌烦,当然可以手工生成一个一个的字节,只要它符合java字节码的规定,它就能被java所识别

  • 但一般没人这么无聊。。。

一个项目里可以同时存在Java和 Groovy代码吗,并且可以互相调用?

  • 可以,参考gradle代码 如 gradle仓库里
    • main里是 java代码
    • test里是 groovy代码
    • 并且它们可以互相调用。所谓的互相调用就是JVM上的互相调用