jvm
什么是字节码,为什么需要字节码
编译 JVM 编译成机器码,
我们看一看 Java 编译过程
- java 源码
- 编译为 class 文件
JVM 接收字节码文件后对其进行校验
验证字节码文件正确性然后通过类加载器加载生成 class 类来运行
【图】
为什么学习字节码?
大家都知道 java 文件编译后为二进制的字节码文件可以被 JVM 读懂,学习好字节码文件可以让我们对 Java 这门语言有深入了解。只要遵循 JVM 规范你就可以创建出自己语言。可以反编译一些第三方库。
java 规范分为两种
- java 语言本身的规范
- JVM 的规范。字节码属于 JVM 规范。JVM 只是关心字节码
这里我们整个字节码分析都会以整个类文件,通过读整个类编译后的字节码来学习字节码。
package com.zidea; public class Tut { private String title = "basic"; private int courses = 10; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getCourses() { return courses; } public void setCourses(int courses) { this.courses = courses; } }
使用 javap 命令查看编译好的 Tut.class 文件
javap Tut.class
public class com.zidea.Tut { public com.zidea.Tut(); public java.lang.String getTitle(); public void setTitle(java.lang.String); public int getCourses(); public void setCourses(int); }
javap -c Tut.class
用命令查看 class 文件我们可以查看到许多助记符。
javap -verbose Tut.class
jangwoodeMacBook-Air:zidea jangwoo$ javap -c Tut.class Compiled from "Tut.java" public class com.zidea.Tut { public com.zidea.Tut(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2 // String basic 7: putfield #3 // Field title:Ljava/lang/String; 10: aload_0 11: bipush 10 13: putfield #4 // Field courses:I 16: return public java.lang.String getTitle(); Code: 0: aload_0 1: getfield #3 // Field title:Ljava/lang/String; 4: areturn public void setTitle(java.lang.String); Code: 0: aload_0 1: aload_1 2: putfield #3 // Field title:Ljava/lang/String; 5: return public int getCourses(); Code: 0: aload_0 1: getfield #4 // Field courses:I 4: ireturn public void setCourses(int); Code: 0: aload_0 1: iload_1 2: putfield #4 // Field courses:I 5: return }
javap -verbose 命令来分析字节码文件
- 魔数
- 版本号
- 常量池
- 类信息 ,class 信息不会丢失在进入 JVM
- 类的构造方法
- 类中的方法信息
- 类变量与成员变量等信息
Classfile /Users/jangwoo/IdeaProjects/jvm_demo/out/production/jvm_demo/com/zidea/Tut.class Last modified May 2, 2019; size 746 bytes MD5 checksum e58553db6eb469ec2411f8711ace986a Compiled from "Tut.java" public class com.zidea.Tut minor version: 0 major version: 54 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #5 // com/zidea/Tut super_class: #6 // java/lang/Object interfaces: 0, fields: 2, methods: 5, attributes: 1 Constant pool: #1 = Methodref #6.#28 // java/lang/Object."<init>":()V #2 = String #29 // basic #3 = Fieldref #5.#30 // com/zidea/Tut.title:Ljava/lang/String; #4 = Fieldref #5.#31 // com/zidea/Tut.courses:I #5 = Class #32 // com/zidea/Tut #6 = Class #33 // java/lang/Object #7 = Utf8 title #8 = Utf8 Ljava/lang/String; #9 = Utf8 courses #10 = Utf8 I #11 = Utf8 <init> #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 LocalVariableTable #16 = Utf8 this #17 = Utf8 Lcom/zidea/Tut; #18 = Utf8 getTitle #19 = Utf8 ()Ljava/lang/String; #20 = Utf8 setTitle #21 = Utf8 (Ljava/lang/String;)V #22 = Utf8 getCourses #23 = Utf8 ()I #24 = Utf8 setCourses #25 = Utf8 (I)V #26 = Utf8 SourceFile #27 = Utf8 Tut.java #28 = NameAndType #11:#12 // "<init>":()V #29 = Utf8 basic #30 = NameAndType #7:#8 // title:Ljava/lang/String; #31 = NameAndType #9:#10 // courses:I #32 = Utf8 com/zidea/Tut #33 = Utf8 java/lang/Object { public com.zidea.Tut(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2 // String basic 7: putfield #3 // Field title:Ljava/lang/String; 10: aload_0 11: bipush 10 13: putfield #4 // Field courses:I 16: return LineNumberTable: line 3: 0 line 4: 4 line 5: 10 LocalVariableTable: Start Length Slot Name Signature 0 17 0 this Lcom/zidea/Tut; public java.lang.String getTitle(); descriptor: ()Ljava/lang/String; flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #3 // Field title:Ljava/lang/String; 4: areturn LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/zidea/Tut; public void setTitle(java.lang.String); descriptor: (Ljava/lang/String;)V flags: (0x0001) ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #3 // Field title:Ljava/lang/String; 5: return LineNumberTable: line 12: 0 line 13: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/zidea/Tut; 0 6 1 title Ljava/lang/String; public int getCourses(); descriptor: ()I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #4 // Field courses:I 4: ireturn LineNumberTable: line 16: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/zidea/Tut; public void setCourses(int); descriptor: (I)V flags: (0x0001) ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: iload_1 2: putfield #4 // Field courses:I 5: return LineNumberTable: line 20: 0 line 21: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/zidea/Tut; 0 6 1 courses I } SourceFile: "Tut.java"
这里我们按顺序了解一下 java 字节码是由哪些部分组成,然后对照创建 Tut
的字节码文件进行分析
字节码整体结构
这张表中是按顺序指出我们字节码中内容。
java 字节码中有两种数据类型
- 字节数据直接量:为基本的数据类型,例如 u1、u2、u4 和 u8,分别代表连续的 1 字节、2 字节、4字节和 8 字节组成整体数据。
- 表(数组):表是由多个基本数据或其他表,按照既定顺序组成的数据集合。例如常量池就是表。
其中表长度是不固定的,他是元素类型(不同类型有不同内容)和元素数量决定。
魔数
所有 class 字节码文件的前 4 个字节都是魔数,魔数值为固定值CA FE BA BE
屏幕快照 2019-05-02 下午8.36.59.png
单个字节,CA 表示一个字节,C 是 16 进制由 4 位来表示16进制,CA 两个在一起表示 8 位。JVM 编译出来的字节码文件是以 8 位字节为最小单位构成。
如果有想学习java的程序员,可来我们的java学习扣qun:697699179,免费送java的视频教程噢!我每晚上8点还会在群内直播讲解Java知识,欢迎大家前来学习哦。
文章来源: https://blog.csdn.net/sdssdfh/article/details/89790776