JVM内部对String类型的处理分析

来源:互联网 发布:mac装win7显卡驱动 编辑:程序博客网 时间:2024/05/01 11:25

首先我们使用例子的形式看看JVM是如何处理String类型的?

1、简单的例子

a. String s1=new String("Hello");

b. String s2="Hello";

c. Object obj=new Object();

 

2、生成的字节码

JVM将上面的程序编译后生成的字节码如下:

a.     0:  new                      #2;    //class java/lang/String

       3:  dup  

       4:  ldc                      #3;    //String Hello

       6:  invokeespecial           #4;    //Method   java/lang/String."<init>":(Ljava/lang/String;) V

       9:  astore_1

b.     10: ldc                      #3;    //String Hello

       12:astore_2

c.     13:new                       #5;    //class java/lang/object

       16:dup

       17:invokespecial             #1;    //Method  java/lang/Object."<init>":()V

       20:astore_3

3、指令解析

new 指令格式:  new indexbyte1,indexbyte2

执行过程:

要执行new指令,JVM通过计算(indexbyte1<<8)|indexbyte2生成一个指向常量池的无符号的16位索引,然后根据这个索引查找JVM常量池的入口。该索引所指向的常量池入口必须为CONSTANT_Class_info。CONSTANT_Class_info有一个tag和一个指向常量池的索引所组成。如果该入口不存在,那么JVM将解析这个常量池入口,该入口类型必须为类。JVM堆中为新的对象映像分配足够大的空间,并将对象的实例变量设置为默认值。最后JVM将指向新的对象的引用objectref压入操作数栈。

 

dup 指令格式:  dup

执行过程:

要执行dup指令,JVM复制了操作数栈顶部一个字长的内容,然后再将复制内容压入栈。本指令能够从操作数栈顶部复制任何单位字长的值。但绝对不要使用它来复制操作数栈顶部任何两个字长(long型或double型)中的一个字长。上面例中,即复制引用objectref,这时在操作数栈存在2个引用。

 

ldc 指令格式:  ldc,index

执行过程:

要执行ldc指令,JVM首先查找index所指定的常量池入口,在index指向的JVM常量池入口,JVM将会查找CONSTANT_Integer_info,CONSTANT_Float_info和CONSTANT_String_info入口。如果还没有这些入口,JVM会解析它们。而对于上面的haha,JVM会找到CONSTANT_String_info入口,同时,将把指向被拘留String对象(由解析该入口的进程产生)的引用压入操作数栈。

 

invokespecial指令格式:  invokespecial indextype1,indextype2

执行过程:
对于该类而言,该指令是用来进行实例初始化方法的调用。上面例子中,即通过其中一个引用调用String类的构造器,初始化对象实例,让另一个相同的引用指向这个被初始化的对象实例,然后前一个引用弹出操作数栈。

 

astore_1指令格式:  astore_1

astore_1指令过程:
要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1。

 

String 类型在编码中字面上的对象,是会进行查询String 常量池表的(如果没有就创建一个String 对象,然后再保存在表中)。而new String()生成的对象是不会查询String常量池表的,它不管表中是否存在,都会创建一个新的String 对象,所以内存地址是肯定不同的。而如果调用String 方法中的intern()方法,则会在String常量池表中查找,然后把该表中的引用返回。

原创粉丝点击