深入java虚拟机--Class文件实例解析
前面发了几篇学习笔记,但是看这些东西总是感觉很"玄乎",来一篇实战的东西来揭一下"JVM"的面纱,让"SSH"时代的童鞋们来熟悉一下Java的"老祖爷"JVM。由于自己的水平有限,所以大家在看过程中发了什么问题,或者您有什么疑问请及时提出来,我及时解决。如果您有什么建议,那么更好大家一块讨论。
1. 源码文件
public class LearningClassFile
{ //普通变量 private int id1; //静态变量 private static int id2; //常量 private final int id3
= 4; //静态常量 private static final int id4
= 5; public LearningClassFile()
{ } public LearningClassFile(int id1,
int id2)
{ this.id1
= id1; this.id2
= id2; } //使用public修饰的addPub方法 public void addPub(int a,
int b)
{ int result
= a + b; System.out.println(result); } //使用private修饰的addPri方法 private void addPri(int a,
int b)
{ int result
= a + b; System.out.println(result); } //使用static修饰的方法 public static void addSta()
{ int result
= id2 + id4; System.out.println(result); } public static final void addFinal(int a,
int b)
{ int result
= a + b; System.out.println(result); } public static void main(String[]
args) { LearningClassFile
lcf = new LearningClassFile(1,
2); lcf.addPub(1,
2); lcf.addPri(1,
2); addSta(); addFinal(1,
2); }} |
Class文件:
Compiled
from "LearningClassFile.java"public class LearningClassFile
extends java.lang.Object SourceFile:
"LearningClassFile.java" minor
version: 0 major
version: 50//运行时常量池:用于存放编译期生成的各种字面量和符号引用。
Constant
pool://从父类Object继承的默认构造方法//观察该方法的特征:无参,返回类型voidconst #1 =
Method #13.#35;
//
java/lang/Object."<init>":()V//常量id3//"#7.#36;
// LearningClassFile.id3:I"//#7:查找常量池中的类名LearningClassFile//#36-->"const
#36 = NameAndType #17:#15;// id3:I"//NameAndType字面的意思是名称和类型。即id3是变量的名称,I表示id3是int类型//综合描述:LearningClassFile中的id3是int类型const #2 =
Field #7.#36;
//
LearningClassFile.id3:Iconst #3 =
Field #7.#37;
//
LearningClassFile.id1:Iconst #4 =
Field #7.#38;
//
LearningClassFile.id2:I//将System的out存储至常量池//System类中out被public
static final修饰的//"public
final static PrintStream out = nullPrintStream();"//综合描述:System类的out属性是PrintStream类型const #5 =
Field #39.#40;
//
java/lang/System.out:Ljava/io/PrintStream;//将PrintStream的Println()方法存储至常量池//该方法的参数为I,返回值为voidconst #6 =
Method #41.#42;
//
java/io/PrintStream.println:(I)V//类LearningClassFIleconst #7 =
class #43;
//
LearningClassFile//构造函数//该构造函数需传入两个int类型的变量const #8 =
Method #7.#44;
//
LearningClassFile."<init>":(II)V//LearningClassFile的addPub方法//#4-->"const
#45 = NameAndType #27:#26;// addPub:(II)V"//#27-->"const
#27 = Asciz addPub;" 方法的名称为:addPub//#26-->"const
#26 = Asciz (II)V;" 方法的类型:两个int类型的参数,返回类型为voidconst #9 =
Method #7.#45;
//
LearningClassFile.addPub:(II)Vconst #10 =
Method #7.#46;
//
LearningClassFile.addPri:(II)Vconst #11 =
Method #7.#47;
//
LearningClassFile.addSta:()Vconst #12 =
Method #7.#48;
//
LearningClassFile.addFinal:(II)Vconst #13 =
class #49;
//
java/lang/Objectconst #14 =
Asciz id1;const #15 =
Asciz I;const #16 =
Asciz id2;const #17 =
Asciz id3;//ConstantValue属性表示一个常量字段的值//即final修饰的属性const #18 =
Asciz ConstantValue;//对于final修饰的常量直接将类型和值存入常量池const #19 =
int 4;const #20 =
Asciz id4;const #21 =
int 5;const #22 =
Asciz <init>;const #23 =
Asciz ()V;//Code属性只为唯一一个方法、实例类初始化方法或类初始化方法保存Java虚拟机指令及相关辅助信息//简而言之:保存方法编译后的指令信息const #24 =
Asciz Code;//java源码行号与编译后的字节码指令的对应表const #25 =
Asciz LineNumberTable;const #26 =
Asciz (II)V;const #27 =
Asciz addPub;const #28 =
Asciz addPri;const #29 =
Asciz addSta;const #30 =
Asciz addFinal;const #31 =
Asciz main;const #32 =
Asciz ([Ljava/lang/String;)V;//java
源码文件const #33 =
Asciz SourceFile;const #34 =
Asciz LearningClassFile.java;const #35 =
NameAndType #22:#23;//
"<init>":()Vconst #36 =
NameAndType #17:#15;//
id3:Iconst #37 =
NameAndType #14:#15;//
id1:Iconst #38 =
NameAndType #16:#15;//
id2:Iconst #39 =
class #50;
//
java/lang/Systemconst #40 =
NameAndType #51:#52;//
out:Ljava/io/PrintStream;const #41 =
class #53;
//
java/io/PrintStreamconst #42 =
NameAndType #54:#55;//
println:(I)Vconst #43 =
Asciz LearningClassFile;const #44 =
NameAndType #22:#26;//
"<init>":(II)Vconst #45 =
NameAndType #27:#26;//
addPub:(II)Vconst #46 =
NameAndType #28:#26;//
addPri:(II)Vconst #47 =
NameAndType #29:#23;//
addSta:()Vconst #48 =
NameAndType #30:#26;//
addFinal:(II)Vconst #49 =
Asciz java/lang/Object;const #50 =
Asciz java/lang/System;const #51 =
Asciz out;const #52 =
Asciz Ljava/io/PrintStream;;const #53 =
Asciz java/io/PrintStream;const #54 =
Asciz println;const #55 =
Asciz (I)V;{//默认构造方法public LearningClassFile(); Code: Stack=2,
Locals=1,
Args_size=1 0:
aload_0 1:
invokespecial #1;
//Method
java/lang/Object."<init>":()V //将id3的引用推送至栈顶 4:
aload_0 //将4推送至栈顶 5:
iconst_4 //将4赋值给id3 6:
putfield #2;
//Field
id3:I 9:
return LineNumberTable: line
11:
0 //public
LearningClassFile() { //对于final类型的实例变量在每个构造方法中都会进行一次初始化。 line
7:
4 //
private final int id3 = 4; line
12:
9 //}public LearningClassFile(int,
int); Code: Stack=2,
Locals=3,
Args_size=3 0:
aload_0 1:
invokespecial #1;
//Method
java/lang/Object."<init>":()V 4:
aload_0 5:
iconst_4 6:
putfield #2;
//Field
id3:I 9:
aload_0 10:
iload_1 11:
putfield #3;
//Field
id1:I 14:
aload_0 15:
pop 16:
iload_2 17:
putstatic #4;
//Field
id2:I 20:
return LineNumberTable: line
14:
0 //public
LearningClassFile(int id1, int id2) { //对于final类型的实例变量在每个构造方法中都会进行一次初始化。 line
7:
4 //
private final int id3 = 4; line
15:
9 //
this.id1 = id1; line
16:
14 //
this.id2 = id2; line
17:
20 //}public void addPub(int,
int); Code: Stack=2,
Locals=4,
Args_size=3 0:
iload_1 1:
iload_2 2:
iadd 3:
istore_3 4:
getstatic #5;
//Field
java/lang/System.out:Ljava/io/PrintStream; 7:
iload_3 8:
invokevirtual #6;
//Method
java/io/PrintStream.println:(I)V 11:
return LineNumberTable: line
21:
0 //
int result = a + b; line
22:
4 //
System.out.println(result); line
23:
11 //
}public static void addSta(); Code: Stack=2,
Locals=1,
Args_size=0 //获取静态变量id2推送至栈顶 0:
getstatic #4;
//Field
id2:I //直接从常量池中取出id4的值5推送至栈顶 3:
iconst_5 //执行相加操作 4:
iadd //将计算结果推送至栈顶 5:
istore_0 //获取静态与out 6:
getstatic #5;
//Field
java/lang/System.out:Ljava/io/PrintStream; //取出计算结果 9:
iload_0 //调用println方法 10:
invokevirtual #6;
//Method
java/io/PrintStream.println:(I)V //方法正常结束 13:
return LineNumberTable: line
33:
0 //
int result = id2 + id4; line
34:
6 //
System.out.println(result); line
35:
13 //}public static final void addFinal(int,
int); Code: Stack=2,
Locals=3,
Args_size=2 0:
iload_0 1:
iload_1 2:
iadd 3:
istore_2 4:
getstatic #5;
//Field
java/lang/System.out:Ljava/io/PrintStream; 7:
iload_2 8:
invokevirtual #6;
//Method
java/io/PrintStream.println:(I)V 11:
return LineNumberTable: line
38:
0 line
39:
4 line
40:
11public static void main(java.lang.String[]); Code: Stack=4,
Locals=2,
Args_size=1 //创建一个LearningClassFile对象,并将对象的引用推送至栈顶 0:
new #7;
//class
LearningClassFile //将对象的引用进行备份推送至栈顶 //使用原有的引用值调用实例方法,现在置于栈顶的引用值的位置将被接下来的操作覆盖。 3:
dup //将构造函数中的参数1推送至栈顶 4:
iconst_1 5:
iconst_2 //执行构造方法 6:
invokespecial #8;
//Method
"<init>":(II)V //将栈顶引用型数值存入第二个本地变量 9:
astore_1 10:
aload_1 11:
iconst_1 12:
iconst_2 //调用实例方法 13:
invokevirtual #9;
//Method
addPub:(II)V 16:
aload_1 17:
iconst_1 18:
iconst_2 19:
invokespecial #10;
//Method
addPri:(II)V //调用静态方法 22:
invokestatic #11;
//Method
addSta:()V 25:
iconst_1 26:
iconst_2 27:
invokestatic #12;
//Method
addFinal:(II)V 30:
return LineNumberTable: line
43:
0 //
LearningClassFile lcf = new LearningClassFile(1, 2); line
44:
10 //
lcf.addPub(1, 2); line
45:
16 //
lcf.addPri(1, 2); line
46:
22 //
addSta(); line
47:
25 //
addFinal(1, 2); line
48:
30 //}}final变量和static final变量的区别: 1.
实例常量和类常量的区别 2.
初识方式不同:从class字节码来看final修饰的变量会出现在每个构造方法中进行一次初始化;static final类型的变量必须在定义的时候进行初始化。 理解"编译期可知,运行期不变":
编译器可确定调用方法的版本,符合这个标准的方法主要有两种:私有方法,静态方法。详情请看:深入理解JVM读书笔记--字节码执行引擎。 |
2. final变量和static final变量的区别: (1) 实例常量和类常量的区别 (2) 初始化方式不同:从class字节码来看final修饰的变量会出现在每个构造方法中进行一次初始化;static final类型的变量必须在定义的时候进行初始化。
3. 理解"编译期可知,运行期不变": 编译器可确定调用方法的版本,符合这个标准的方法主要有两种:私有方法,静态方法。详情请看:深入理解JVM读书笔记--字节码执行引擎。
如果你喜欢本文, 请长按二维码,关注公众号 分布式编程.
作者:分布式编程
出处:https://zthinker.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
浙公网安备 33010602011771号