随笔-46  评论-64  文章-2  trackbacks-0
new & valueof & 直接赋值的区别
首先来看下面这段代码
public static void main(String[] args) {
  String s1 = "s1";
  String s2 = new String("s2");
  String s3 = String.valueOf(12345);
}
 
编译成class文件之后,使用eclipse class file viewer查看
 
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 3, Locals: 4
  public static void main(java.lang.String[] args);
     0  ldc <String "s1"> [16]
     2  astore_1 [s1]

     3  new java.lang.String [18]
     6  dup
     7  ldc <String "s2"> [20]
     9  invokespecial java.lang.String(java.lang.String) [22]
    12  astore_2 [s2]
    13  sipush 12345
    16  invokestatic java.lang.String.valueOf(int) : java.lang.String [25]
    19  astore_3 [s3]

    20  return
      Line numbers:
        [pc: 0, line: 12]
        [pc: 3, line: 13]
        [pc: 13, line: 14]
        [pc: 20, line: 20]
      Local variable table:
        [pc: 0, pc: 21] local: args index: 0 type: java.lang.String[]
        [pc: 3, pc: 21] local: s1 index: 1 type: java.lang.String
        [pc: 13, pc: 21] local: s2 index: 2 type: java.lang.String
        [pc: 20, pc: 21] local: s3 index: 3 type: java.lang.String
}
 
对于第一行代码 String s1 = "s1"; 编译成字节码之后,对应两条指令,
  1. ldc指令从运行时常量池push一个值到Frame的操作数栈上面,这个值在这里就是"s1"字符串的引用,
  2. astore指令将objectref存储到局部变量,这里也就是存储到局部变量s1。
 
对于第二行代码   String s2 = new String("s2");编译成字节码之后,对于的指令也用高亮标注出来了,这里把操作数栈的情况画了出来,希望能帮助理解。橙色标注的为栈顶元素。
  1. new指令会在堆上创建对象,操作数栈里压入创建的objectref,
     
    objectref
    ...
  2. dup指令复制操作数栈顶的元素, 
    objectref
    objectref
    ...
  3. ldc指令依然是从常量池push一个值到Frame的操作数栈上,这个值是"s2"字符串的引用。 
    "s2"_ref
    objectref
    objectref
    ...
  4. invokespecial 指令调用一个方法,这里就是调用String的构造函数,调用完成之后栈上还有一个objectref 
    objectref
    ...
  5. astore指令将objectref存储到局部变量,这里也就是存储到局部变量s2。 
                
    ...
 
对于第三行代码  String s3 = String.valueOf(12345); 编译成字节码之后对应的指令,
  1. sipush 将 12345 压栈
  2. invokestatic 调用 String.valueof(int) 方法
  3. astore 将栈顶的对象引用存储到本地变量s3 (这里不再深究这个栈顶元素是怎么来的了)
 
PMD检查代码的时候,有这样的warning: Avoid instantiating String objects.Call String.valueOf() instead. PMD给出的原因是In JDK 1.5, calling new String() causes memory allocation. String.valueOf() is more memory friendly.
 
经过上面的分解,我们应该知道原因了,以后写代码的时候,初始化一个字符串,  String s1 = "s1"; 这样的代码肯定比  String s2 = new String("s2");代码强,将其他类型的值转换成String的时候,valueof方法比new方法效率也高。

 
备注:
A frame is used to store data and partial results(局部变量,操作数栈), as well as to perform dynamic linking , return values for methods, and dispatch exceptions.
 
ldc指令的操作数栈: ...->...,value (value是int,float 或者 string 类型的引用)
astore的操作数栈: ...,objectref->...
new指令的操作数栈: ...->...,objectref
dup指令的操作数栈: ...,value->...,value,value
invokespecial的操作数栈: ...,objectref, [agr1,[arg2...]]->...
invloestatic的操作数栈:..., [arg1, [arg2...]] -> ...

 
如果要理解的更透彻建议阅读以下参考资料:
posted on 2008-07-28 14:27 jht 阅读(1691) 评论(1)  编辑  收藏 所属分类: J2SE

评论:
# re: new & valueof & 直接赋值的区别 2008-07-28 23:29 | 隔叶黄莺
其实不用到字节码里去,看 valueOf() 方法的源代码大家就能明白是怎么回事,应该用 valueOf() 而不是 new.  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: