前面发了几篇学习笔记,但是看这些东西总是感觉很"玄乎",来一篇实战的东西来揭一下"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继承的默认构造方法 //观察该方法的特征:无参,返回类型void const # 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:I const # 3 =
Field # 7 .# 37 ;
//
LearningClassFile.id1:I const # 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/PrintS tream; //将PrintStream的Println()方法存储至常量池 //该方法的参数为I,返回值为void const # 6 =
Method # 41 .# 42 ;
//
java/io/PrintStream.println:(I)V //类LearningClassFIle const # 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类型的参数,返回类型为void const # 9 =
Method # 7 .# 45 ;
//
LearningClassFile.addPub:(II)V const # 10 =
Method # 7 .# 46 ;
//
LearningClassFile.addPri:(II)V const # 11 =
Method # 7 .# 47 ;
//
LearningClassFile.addSta:()V const # 12 =
Method # 7 .# 48 ;
//
LearningClassFile.addFinal:(II)V const # 13 =
class # 49 ;
//
java/lang/Object const # 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>":()V const # 36 =
NameAndType # 17 :# 15 ; //
id3:I const # 37 =
NameAndType # 14 :# 15 ; //
id1:I const # 38 =
NameAndType # 16 :# 15 ; //
id2:I const # 39 =
class # 50 ;
//
java/lang/System const # 40 =
NameAndType # 51 :# 52 ; //
out:Ljava/io/PrintStream; const # 41 =
class # 53 ;
//
java/io/PrintStream const # 42 =
NameAndType # 54 :# 55 ; //
println:(I)V const # 43 =
Asciz LearningClassFile; const # 44 =
NameAndType # 22 :# 26 ; //
"<init>":(II)V const # 45 =
NameAndType # 27 :# 26 ; //
addPub:(II)V const # 46 =
NameAndType # 28 :# 26 ; //
addPri:(II)V const # 47 =
NameAndType # 29 :# 23 ; //
addSta:()V const # 48 =
NameAndType # 30 :# 26 ; //
addFinal:(II)V const # 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 :
11 public 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读书笔记--字节码执行引擎。