对于一个写好的java程序来说。第一步就是把把java代码编译成字节码,生成一个class文件,并将这个这个Class文件交个JVM去解析,然后调用本机的机器吗执行。接下来通过一个简单的列子分析一下编译的class文件
第一步先编写一个简单的java文件
package com.example.demo;
public class ByteCode {
public static void main(String[] args) {
int i = 1;
int j = 5;
i++;
++j;
System.out.println(i);
System.out.println(j);
}
}
然后到当前java文件的目录下在intellIj的控制台或者windows的cmd执行javac java文件名.java
在当前的目录在就会生成一个和java文件名相同的以.class结尾的calss文件。这就是java的字节码文件,也就JVM需要的文件。
这个文件我们可以反编译来看一下在执行了javac后生成的class文件里到底有什么,可以直接用intellij直接打开,也可以执行javap -c class文件名(不要.class)
这里我两种都试过了
用intellij直接打开:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.example.demo;
public class ByteCode {
public ByteCode() {
}
public static void main(String[] var0) {
byte var1 = 1;
byte var2 = 5;
int var3 = var1 + 1;
int var4 = var2 + 1;
System.out.println(var3);
System.out.println(var4);
}
}
这里我们可以很直观的看到,在缺省构造函数的情况下。编译成class文件后自动加上无参的构造函数。
执行javap -c 后
Compiled from "ByteCode.java"
public class com.example.demo.ByteCode {
public com.example.demo.ByteCode();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_5
3: istore_2
4: iinc 1, 1
7: iinc 2, 1
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
13: iload_1
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload_2
21: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
24: return
}
接下来分析一下这些代码
Compiled from “ByteCode.java”:表示这个class文件是由ByteCode.java编译而来的
public com.example.demo.ByteCode();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
这个就是在缺省构造函数的情况下,默认加上的无参构造函数。
0:aload_0:代表第一次操作
1:invokespecial:表示调用父类的构造函数
4:return:表示退出函数
public static void main(java.lang.String[]);
Code:
//表示将常量1放入栈顶
0: iconst_1
//表示将栈顶的值放到局部变量1中
1: istore_1
//下面两部和上面两部目的是一样的
2: iconst_5
3: istore_2
//分别将变量1和2加1
4: iinc 1, 1
7: iinc 2, 1
//获得Printream对象并将其放入栈顶
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
//将变量值1放入栈顶
13: iload_1
//使用PrintStream的println()方法获取并打印打印变量1
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
//和上面一样
17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload_2
21: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
//退出方法
24: return