论坛首页 Java企业应用论坛

JAVA class文件研究2

浏览 2417 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2014-03-06  

本章,我将采用一个例子来讲解class文件结构,并介绍jvm是如何操作分配内存的。

我们新建一个类,设置了两个比较简单的例子,就是创建String的,因为这个类对象处理起来有点特殊,所以拿过来作为例子来讲解

public class StringKnowledgeTest {
	public String getName(){
		String fengfuName="fengfu";
		return fengfuName;
	}
	public String getnewName(){
		String zhaoff=new String("zhaoff");//这语句,一共生成了几个对象
		return zhaoff;
	}
}

     使用javap -verbose StringKnowledgeTest 查看类结构

     常量池为:

     

const #1 = class #2; // knowledgeTest/StringKnowledgeTest 
const #2 = Asciz knowledgeTest/StringKnowledgeTest; 
const #3 = class #4; // java/lang/Object 
const #4 = Asciz java/lang/Object; 
const #5 = Asciz ; 
const #6 = Asciz ()V; 
const #7 = Asciz Code; 
const #8 = Method #3.#9; // java/lang/Object."":()V 
const #9 = NameAndType #5:#6;// "":()V 
const #10 = Asciz LineNumberTable; 
const #11 = Asciz LocalVariableTable; 
const #12 = Asciz this; 
const #13 = Asciz LknowledgeTest/StringKnowledgeTest;; 
const #14 = Asciz getName; const #15 = Asciz ()Ljava/lang/String;; 
const #16 = String #17; // fengfu 
const #17 = Asciz fengfu; 
const #18 = Asciz fengfuName; 
const #19 = Asciz Ljava/lang/String;; 
const #20 = Asciz getnewName; 
const #21 = class #22; // java/lang/String 
const #22 = Asciz java/lang/String; 
const #23 = String #24; // zhaoff 
const #24 = Asciz zhaoff; 
const #25 = Method #21.#26; // java/lang/String."":(Ljava/lang/String;)V 
const #26 = NameAndType #5:#27;// "":(Ljava/lang/String;)V 
const #27 = Asciz (Ljava/lang/String;)V; 
const #28 = Asciz SourceFile; 
const #29 = Asciz StringKnowledgeTest.java;

       从常量池中第17个来看,方法getName中的String "fengfu"在经过编译后,就会被保存到常量池中,方法getnewName也是这样,"zhaoff"经过编译后,会放入class常量池中,并最终内存方法区中。

getName对应的jvm指令为:

public java.lang.String getName();
  Code:
   Stack=1, Locals=2, Args_size=1
   0: ldc #16; //String fengfu  //该操作为:从运行时常量池中提取数据推入操作数栈,reference类型则为推入reference类型
   2: astore_1   //该操作为:将一个reference类型数据保存到局部变量表
   3: aload_1    //该操作为:从局部变量表中读取一个reference类型到操作数栈
   4: areturn    //从操作数栈返回一个reference数据,结束方法
  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      5      0    this       LknowledgeTest/StringKnowledgeTest;
   3      2      1    fengfuName       Ljava/lang/String;

      jvm指令的整个过程,都是操作局部变量表与操作数栈,通过出入栈方式来完成该方法。

本过程一个只生成了一个字符串常量,并且在编译后,就保存在了class文件常量池中。

执行过程中局部变量表和操作数栈的变化如下:

      

 getnewName方法对应的jvm指令如下:

public java.lang.String getnewName();
  Code:
   Stack=3, Locals=2, Args_size=1
   0: new #21; //class java/lang/String  //new 一个 String 并将该String的reference压入操作数栈
   3: dup     //复制操作数栈栈顶的值,并压入操作数栈
   4: ldc #23; //String zhaoff  //该操作为:从运行时常量池中提取数据推入操作数栈,reference类型则为推入reference类型
   6: invokespecial #25; //Method java/lang/String."":(Ljava/lang/String;)V //调用String 构造函数
   9: astore_1  //该操作为:将一个reference类型数据保存到局部变量表
   10: aload_1   //该操作为:从局部变量表中读取一个reference类型到操作数栈
   11: areturn  //从操作数栈返回一个reference数据,结束方法

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      12      0    this       LknowledgeTest/StringKnowledgeTest;
   10      2      1    zhaoff       Ljava/lang/String;

 执行过程中局部变量表和操作数栈的变化如下:



       总结,从上面可以看出来,new String("abc") 产生了两个对象,要比String test="ABC"jvm指令要复杂,而且产生的对象也要多一个。第二种方式虽然产生了一个对象,但该对象位于常量池中,后期再次使用到"ABC"时,会服用常量池中的该变量。

  • 大小: 37.4 KB
  • 大小: 101.2 KB
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics