计算机不能直接运行java代码,要先运行虚拟机,再由java虚拟机运行编译后java代码。
为什么不能直接运行java代码?
计算机所有的操作都是通过一个个指令集汇集后去完成的。java 是高级语言,只有人才能理解它的逻辑,机器是无法识别。所以需要将java文件编译成JVM能后识别的字节码文件,这样JVM才能正确的识别代码转换后的指令去正确的执行它。
- java代码转换成字节码文件后,在交由部署到不同平台JVM去读取执行。从而实现了一次编译,到处运行。
- JVM 不只是支持java,衍生了很多基于JVM的语言,如Groovy、Scala、Koltin、JRuby、Jython等
Java字节码文件
class文件本质上是一个以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在class文件中。jvm根据其特定的规则解析该二进制数据,从而得到相关信息。
class文件结构属性
-
魔数:每一个.class文件的前四个字节成为魔数,值为
0xCAFEBABE
(咖啡宝贝?) 用来确定文件是一个.class文件,很多类型的文件都是有魔数的,只靠文件名是不能确定文件类型的,所以每种文件都有对应的魔数来标识它,比如: jpg、png 等 -
次版本和主版本:用来表示编一个class文件使用的jdk版本,次版本一版为0,如果主版本号为0034转化为十进制是52,在jdk 1.0和1.1 使用了45,以后每一个大版本在上一个版本的基础上加一。可以看看出jdk是 1.8.0
-
常量池: 用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)
-
访问标记:用于表示该class的访问类型和属性,比如访问类型是不是pulic,能不能被标记为final
-
父类索引、类索引、接口索引:通过这三种索引来描述类的继承关系
-
字段表属性:用于描述接口或类中声明的变量,比如:变量的作用域、是不是静态变量、 数据类型
-
方法表属性:和字段表属性类似,只不过用于描述方法的类型和作用域
-
属性表属性:用于描述特定场景的信息,比如:字段表属性的特殊属性等
生成一个class文件
javac UserDTO.java
使用javac
命令会在同一路径下生成一个跟文件同名的.class文件
反编译.class文件
javap -v UserDTO.class
$ javap -v UserDTO.class
Classfile /C:/Users/zhaotianxin/Desktop/hzero_c7n/redis/src/main/java/icu/fastwo
rm/redis/UserDTO.class
Last modified 2021-8-4; size 831 bytes
MD5 checksum 48a05888aaba92b73e52e159bb7fd612
Compiled from "UserDTO.java"
public class icu.fastworm.redis.UserDTO implements java.io.Serializable
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#29 // java/lang/Object."<init>":()V
#2 = Fieldref #5.#30 // icu/fastworm/redis/UserDTO.name:Lja
va/lang/String;
#3 = Fieldref #5.#31 // icu/fastworm/redis/UserDTO.word:Lja
va/lang/String;
#4 = Fieldref #5.#32 // icu/fastworm/redis/UserDTO.id:Ljava
/lang/Long;
#5 = Class #33 // icu/fastworm/redis/UserDTO
#6 = Class #34 // java/lang/Object
#7 = Class #35 // java/io/Serializable
#8 = Utf8 id
#9 = Utf8 Ljava/lang/Long;
#10 = Utf8 name
#11 = Utf8 Ljava/lang/String;
#12 = Utf8 word
#13 = Utf8 <init>
#14 = Utf8 (Ljava/lang/String;Ljava/lang/String;)V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 getId
#18 = Utf8 ()Ljava/lang/Long;
#19 = Utf8 setId
#20 = Utf8 (Ljava/lang/Long;)V
#21 = Utf8 getName
#22 = Utf8 ()Ljava/lang/String;
#23 = Utf8 setName
#24 = Utf8 (Ljava/lang/String;)V
#25 = Utf8 getWord
#26 = Utf8 setWord
#27 = Utf8 SourceFile
#28 = Utf8 UserDTO.java
#29 = NameAndType #13:#36 // "<init>":()V
#30 = NameAndType #10:#11 // name:Ljava/lang/String;
#31 = NameAndType #12:#11 // word:Ljava/lang/String;
#32 = NameAndType #8:#9 // id:Ljava/lang/Long;
#33 = Utf8 icu/fastworm/redis/UserDTO
#34 = Utf8 java/lang/Object
#35 = Utf8 java/io/Serializable
#36 = Utf8 ()V
{
public icu.fastworm.redis.UserDTO(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>
":()V
4: aload_0
5: aload_1
6: putfield #2 // Field name:Ljava/lang/String;
9: aload_0
10: aload_2
11: putfield #3 // Field word:Ljava/lang/String;
14: return
LineNumberTable:
line 16: 0
line 17: 4
line 18: 9
line 19: 14
public java.lang.Long getId();
descriptor: ()Ljava/lang/Long;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #4 // Field id:Ljava/lang/Long;
4: areturn
LineNumberTable:
line 22: 0
public void setId(java.lang.Long);
descriptor: (Ljava/lang/Long;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #4 // Field id:Ljava/lang/Long;
5: return
LineNumberTable:
line 26: 0
line 27: 5
public java.lang.String getName();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field name:Ljava/lang/String;
4: areturn
LineNumberTable:
line 30: 0
public void setName(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #2 // Field name:Ljava/lang/String;
5: return
LineNumberTable:
line 34: 0
line 35: 5
public java.lang.String getWord();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #3 // Field word:Ljava/lang/String;
4: areturn
LineNumberTable:
line 38: 0
public void setWord(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #3 // Field word:Ljava/lang/String;
5: return
LineNumberTable:
line 42: 0
line 43: 5
}
SourceFile: "UserDTO.java"
常量池
字面量
字面量类似于java中的常量概念,如文本字符串,final常量等
符号引用
- 类和接口的全限定名(Fully Qualified Name)
- 字段的名称和描述符号(Descriptor)
- 方法的名称和描述符