什么是字节码
Java bytecode是由单个(byte)组成,理论上最多支持256个操作码(opcode)。实际上Java只用了200多个左右的操作码,还有一些操作码留给调试操作。
根据操作码的性质主要分为四大类
- 栈操作指令,包括与局部变量操作指令
- 程序流程控制指令
- 对象操作指令,包括方法调用指令
- 算数运算及类型转换指令
生成字节码
写一个最简单的类源码如下
package demo.jvm0104;
public class HelloByteCode{
public static void main(String[] args){
HelloByteCode obj=new HelloByteCode();
}
}
编译:javac demo/jvm0104/HelloByteCode.java
查看字节码:javap -c demo.jvm0104/HelloByteCode
Compiled from "HelloByteCode.java"
public class demo.jvm0104.HelloByteCode {
public demo.jvm0104.HelloByteCode();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class demo/jvm0104/HelloByteCode
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: return
}
复杂点的例子:javap -c -verbose demo.java0104.Hello
Classfile /C:/Users/29328/Desktop/abc/demo/jvm0104/HelloByteCode.class
Last modified 2021-3-6; size 301 bytes
MD5 checksum 542cb70faf8b2b512a023e1a8e6c1308
Compiled from "HelloByteCode.java"
public class demo.jvm0104.HelloByteCode
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#13 // java/lang/Object."<init>":()V
#2 = Class #14 // demo/jvm0104/HelloByteCode
#3 = Methodref #2.#13 // demo/jvm0104/HelloByteCode."<init>":()V
#4 = Class #15 // java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 main
#10 = Utf8 ([Ljava/lang/String;)V
#11 = Utf8 SourceFile
#12 = Utf8 HelloByteCode.java
#13 = NameAndType #5:#6 // "<init>":()V
#14 = Utf8 demo/jvm0104/HelloByteCode
#15 = Utf8 java/lang/Object
{
public demo.jvm0104.HelloByteCode();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class demo/jvm0104/HelloByteCode
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: return
LineNumberTable:
line 5: 0
line 6: 8
}
SourceFile: "HelloByteCode.java"
字节码运行时节构
Jvm是一台基于栈的独立计算机。
每个线程都有自己独立的线程栈(Jvm Stack),用于存储自己的栈帧(Frame)。
每次操作Jvm都会创建自己的栈帧,栈帧由操作数栈,局部变量数组及Class引用组成。
Class引用指向当前运行时常量中对应的Class类。
四则运算例子
- 编写MovingAverage.java类
package demo.jvm0104;
/**
* 移动平均数
*/
public class MovingAverage{
private int count=0;
private double sum=0.0D;
public void submit(double value){
this.count++;
this.sum+=value;
}
public double getAvg(){
if(0==this.count){
return sum;
}else{
return this.sum/this.count;
}
}
}
- 编译:javac -encoding utf-8 demo/jvm0104/MovingAverage.java
查看字节码:javap -c demo.jvm0104.MovingAverage
Compiled from "MovingAverage.java"
public class demo.jvm0104.MovingAverage {
public demo.jvm0104.MovingAverage();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_0
6: putfield #2 // Field count:I
9: aload_0
10: dconst_0
11: putfield #3 // Field sum:D
14: return
public void submit(double);
Code:
0: aload_0
1: dup
2: getfield #2 // Field count:I
5: iconst_1
6: iadd
7: putfield #2 // Field count:I
10: aload_0
11: dup
12: getfield #3 // Field sum:D
15: dload_1
16: dadd
17: putfield #3 // Field sum:D
20: return
public double getAvg();
Code:
0: iconst_0
1: aload_0
2: getfield #2 // Field count:I
5: if_icmpne 13
8: aload_0
9: getfield #3 // Field sum:D
12: dreturn
13: aload_0
14: getfield #3 // Field sum:D
17: aload_0
18: getfield #2 // Field count:I
21: i2d
22: ddiv
23: dreturn
}
- 编写LocalVariableTest.java类
package demo.jvm0104;
public class LocalVariableTest{
public static void main(String[] args){
MovingAverage ma=new MovingAverage();
int num1=1;
int num2=2;
ma.submit(num1);
ma.submit(num2);
double avg=ma.getAvg();
}
}
- 编译:javac -encoding utf-8 demo/jvm0104/LocalVariableTest.java
查看字节码:javap -c demo.jvm0104.LocalVaiableTest
Compiled from "LocalVariableTest.java"
public class demo.jvm0104.LocalVariableTest {
public demo.jvm0104.LocalVariableTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class demo/jvm0104/MovingAverage
3: dup
4: invokespecial #3 // Method demo/jvm0104/MovingAverage."<init>":()V
7: astore_1
8: iconst_1
9: istore_2
10: iconst_2
11: istore_3
12: aload_1
13: iload_2
14: i2d
15: invokevirtual #4 // Method demo/jvm0104/MovingAverage.submit:(D)V
18: aload_1
19: iload_3
20: i2d
21: invokevirtual #4 // Method demo/jvm0104/MovingAverage.submit:(D)V
24: aload_1
25: invokevirtual #5 // Method demo/jvm0104/MovingAverage.getAvg:()D
28: dstore 4
30: return
算术操作与类型转化
add(+) | sub(-) | mult(*) | divide(/) | remainder(%) | negate(-) | |
---|---|---|---|---|---|---|
int | iadd | isub | imul | idiv | irem | ineg |
long | ladd | lsub | lmul | ldiv | lrem | lneg |
float | fadd | fsub | fmul | fdiv | frem | fneg |
double | dadd | dsub | dmul | ddiv | drem | dneg |
int | long | float | double | byte | char | short | |
---|---|---|---|---|---|---|---|
int | - | i2l | i2f | i2d | i2b | i2c | i2s |
long | l2i | - | l2f | l2d | - | - | - |
float | f2i | f2l | - | f2d | - | - | - |
double | d2i | d2l | d2f | - | - | - | - |