前面发了几篇学习笔记,但是看这些东西总是感觉很"玄乎",来一篇实战的东西来揭一下"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、理解"编译期可知,运行期不变":
编译器可确定调用方法的版本,符合这个标准的方法主要有两种:私有方法,静态方法。
原文链接:http://www.cnblogs.com/focusj/archive/2012/03/05/2375357.html
【编辑推荐】