万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 大纲

  • 走近Java

  • 内存与垃圾回收

  • 字节码与类加载

    • JVM基石:class文件
      • 字节码文件的跨平台性
      • Java的前端编译器
      • 代码细节-字节码
      • 反解析class文件
    • class文件结构
    • javap解析class文件
    • 字节码指令集
    • 类加载过程(类生命周期)
    • 再谈类加载器
    • JVM指令手册
    • class字节码文件结构
  • 性能监控与调优

  • 监控与性能调优案例

  • Java虚拟机
  • 字节码与类加载
2022-03-12
目录

JVM基石:class文件

# JVM基石:class文件

Java是夸平台的语言,JVM是夸语言的平台。JVM能够成为夸语言的平台与字节码是息息相关的。

# 字节码文件的跨平台性

Java虚拟机不和包括Java在内的任何语言绑定,它只与“class”文件这种特定的二进制文件格式所关联。无论是使用哪种语言进行开发,只要能将源文件编译为正确的class文件,那么这种语言就可以在Java虚拟机上执行。可以说,统一而强大的Class文件结构就是Java虚拟机的基石、桥梁。

class_sys_introd_1

虽然JVM的家族庞大,但是所有的JVM全部遵循Java虚拟机规范 (opens new window),也就是说所有的JVM都可以加载符合JVM规范的字节码文件。而我们知道要想让一个Java程序正确地运行在JVM中,Java源码就必须被编译为符合JVM规范的字节码。

一般Java源码的编译过程如下:

  • 前端编译器将符合Java语法规范的Java代码转换为符合JVM规范的字节码文件。
  • javac是一种能够将Java源码编译为字节码的前端编译器。编译过程主要包含了四个步骤:词法解析、语法解析、语义解析以及生成字节码。

class_sys_introd_2

# Java的前端编译器

在学习了JVM的解释引擎之后,就知道我们通常说的“编译代码”,其实指的是前端编译器,也就是编译源代码生成字节码的阶段。而解释引擎的JIT编译器我们通常称为后端编译器,我们所指的编译期优化一般是指JIT运行时所做的优化。

HotSpot VM并没有强制要求前端编译器只能用javac来编译字节码,其实只要编译结果符合JVM规范都可以被JVM所识别。在Java的前端编译器领域,除了javac之外,还有一种经常被大家用到的前端编译器,那就是内置代Eclipse的ECJ(Eclipse Complier for Java)编译器,和javac全量编译方式不同,ECJ是一种增量式编译器。

  • 在Eclipse中,当开发人员编写完代码后,用“Ctrl + S” 快捷键时,ECJ编译器采取的编译方案是把未编译部分的源码逐行进行编译,而非每次都全量编译。因此ECJ编译器效率会比javac编译更加迅速和高效,当然编译质量和javac相比大致是一样的。

    ECJ编译器不仅是Eclipse的默认内置前端编译器,在Tomcat中同样也是使用ECJ编译器来编译JSP文件。由于ECJ编译器是采用GPLv2的开源协议进行源代码公开,所以,大家可以登录Eclipse官方下载ECJ编译器的源码进行二次开发。

  • 默认情况下,IntelliJ IDEA使用的是javac编译器。(可以自己设置为AspectJ编译器,ajc)

class_sys_introd_3

# 代码细节-字节码

字节码有时候也是面试可能会问到的,因为很多时候可以通过对字节码的阅读,了解Java代码底层的执行操作,例如自动装箱拆箱、字符串细节、类加载变量初始化等等细节。

BAT面试题

类文件结构有哪几个部分

知道字节码吗?字节码有哪些?Integer x = 5; int y = 5; 比较x == y都经过那些步骤?

# 自动装箱拆箱

Integer x = 5;
int y = 5;
System.out.println(x == y);

字节码:

 0 iconst_5
 1 invokestatic #2 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
 4 astore_1
 5 iconst_5
 6 istore_2
 7 getstatic #3 <java/lang/System.out : Ljava/io/PrintStream;>
10 aload_1
11 invokevirtual #4 <java/lang/Integer.intValue : ()I> 
14 iload_2
15 if_icmpne 22 (+7)
18 iconst_1
19 goto 23 (+4)
22 iconst_0
23 invokevirtual #5 <java/io/PrintStream.println : (Z)V>
26 return

# 字符串细节

public static void main(String[] args) {
    String str = new String("hello") + new String("world");
    String str1 = "helloworld";
    System.out.println(str == str1);
}

字节码,执行原因可阅读StringTable:

 0 new #2 <java/lang/StringBuilder>
 3 dup
 4 invokespecial #3 <java/lang/StringBuilder.<init> : ()V>
 7 new #4 <java/lang/String>
10 dup
11 ldc #5 <hello>
13 invokespecial #6 <java/lang/String.<init> : (Ljava/lang/String;)V>
16 invokevirtual #7 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
19 new #4 <java/lang/String>
22 dup
23 ldc #8 <world>
25 invokespecial #6 <java/lang/String.<init> : (Ljava/lang/String;)V>
28 invokevirtual #7 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
31 invokevirtual #9 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
34 astore_1
35 ldc #10 <helloworld>
37 astore_2
38 getstatic #11 <java/lang/System.out : Ljava/io/PrintStream;>
41 aload_1
42 aload_2
43 if_acmpne 50 (+7)
46 iconst_1
47 goto 51 (+4)
50 iconst_0
51 invokevirtual #12 <java/io/PrintStream.println : (Z)V>
54 return

# 反解析class文件

Java源代码经过前端编译器后生成的字节码文件是一种二进制的类文件,它的内容是JVM指令(又称字节码指令,例如上面的例子),而不像C、C++经由编译器直接生成机器码。

  • 字节码指令(byte code):Java虚拟机的指令由一个字节长度的、代表某种特定操作含义的操作码(opcode)以及跟随其后的零个或多个代表此操作所需的操作数(operand)所构成。虚拟机中许多指令并不包含操作数,只有一个操作码。
  • 简单来说,字节码指令 = 操作码 [操作数]

通常有三种方式放解析class文件二进制字节码:

  • 人工解析:使用文本编辑器打开,或者工具打开,根据一个个二进制去看,例如,Notepad++安装HEX-Editor插件、Binary Viewer。
  • 使用javap指令:JDK自带的反解析工具。
  • IDEA插件 jclasslib 或 jclasslib bytecode viewer客户端工具。
上次更新: 5/28/2023, 10:57:53 PM
class文件结构

class文件结构→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式