为什么在我的字符串连接字节码中调用“String.valueOf(Object)”?

时间:2013-05-03 17:01:36

标签: java bytecode jvm-hotspot

我在一个小型微基准测试应用程序(运行JDK 1.6)中有以下两种方法:

public static String testStringBuilder3(String str1, String str2, String str3, String str4, String str5) {
    return new StringBuilder(str1).append("-").append(str2).append("-").append(str3).append("-").append(str4).append("-").append(str5).toString();
}

public static String testStringBuilder4(String str1, String str2, String str3, String str4, String str5) {
    return str1 + "-" + str2 + "-" + str3 + "-" + str4 + "-" + str5;
}

我希望这两种方法的字节码相同。它们几乎完全相同,只有一点我不想理解。

这是第一种方法的字节码(我不能让StackOverflow正确格式化):

public static java.lang.String testStringBuilder3(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
Code:
  0:    new #164; //class java/lang/StringBuilder
  3:    dup
  4:    aload_0
  5:    invokespecial   #170; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  8:    ldc #182; //String -
 10:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 13:    aload_1
 14:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 17:    ldc #182; //String -
 19:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 22:    aload_2
 23:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 26:    ldc #182; //String -
 28:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 31:    aload_3
 32:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 35:    ldc #182; //String -
 37:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 40:    aload   4
 42:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 45:    invokevirtual   #176; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
 48:    areturn

这是第二种方法的字节码:

public static java.lang.String testStringBuilder4(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
Code:
  0:    new #164; //class java/lang/StringBuilder
  3:    dup
  4:    aload_0
  5:    invokestatic    #166; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  8:    invokespecial   #170; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  11:   ldc #182; //String -
  13:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  16:   aload_1
  17:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  20:   ldc #182; //String -
  22:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  25:   aload_2
  26:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  29:   ldc #182; //String -
  31:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  34:   aload_3
  35:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  38:   ldc #182; //String -
  40:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  43:   aload   4
  45:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  48:   invokevirtual   #176; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  51:   areturn

两者之间的唯一区别是第二种方法的以下字节码行:

   5:   invokestatic    #166; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;

可能会做什么?

1 个答案:

答案 0 :(得分:5)

来自JDK来源:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

确保第一个变量不为null,否则会抛出NullPointerException,因为这是StringBuilder(String str)的预期行为

实施例

public class StringTest
{
  public static void main(String a[])
  {
    System.out.println(testStringBuilder3(null, null, null, null, null));
    System.out.println(testStringBuilder4(null, null, null, null, null));
  }
 public static String testStringBuilder3(String str1, String str2, String str3, String str4, String str5) {
    return str1 + "-" + str2 + "-" + str3 + "-" + str4 + "-" + str5;
  }
  public static String testStringBuilder4(String str1, String str2, String str3, String str4, String str5) {
    return new StringBuilder(str1).append("-").append(str2).append("-").append(str3).append("-").append(str4).append("-").append(str5).toString();
  }
}

输出:

null-null-null-null-null
Exception in thread "main" java.lang.NullPointerException
    at java.lang.StringBuilder.<init>(Unknown Source)
    at StringTest.testStringBuilder3(StringTest.java:15)
    at StringTest.main(StringTest.java:11)