String字符串

String 对象是不可变的。String类中的每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。

重载“+”与StringBuilder:

String对象具有只读属性,所以指向它的任何引用都不可能改变它的值。因此,也就不会对其他的引用有什么影响。

不可变性会带来一定的效率问题。为String对象重载的“+”操作符就是一个例子。重载的意思是,一个操作符在用于特定的类时,被赋予了特殊的意义(用于String的“+”与“+=”是java中仅有的两个重载过的操作符,而JAVA不允许程序员吃那个在任何操作符)

操作符“+”可以用来连接String。

public class StringTest {
public static void main(String[] args) {
String mango="mango";
String s="a"+mango+"b";
System.out.println(s);
}
}

通过jdk自带的javap可以反编译以上代码,命令如下:

javap -c StringTest


得到以下代码:
Compiled from "StringTest.java"
public class StringTest {
  public StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return


  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String mango
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #5                  // String a
      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: aload_1
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: ldc           #7                  // String b
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

      27: astore_2
      28: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: aload_2
      32: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      35: return
}


从绿色背景的代码段中可以看到java.lang.StringBuilder类的引入。虽然我们没有使用这个类,但是编译器自主的使用了它,因为它更高效。

在上面的例子里面,编译器创建了一个StringBuilder对象,用以构造最终的String,并为每个字符串调用一次append()方法,共3次,最后调用toString()生成结果,并存储为s。

虽然这样看来编译器会自动优化性能,但是在写两个一下方法:

public String implicit(String[] fields){
String result="";
for (int i = 0; i < fields.length; i++) {
result+=fields[i];
}
return result;
}


public String expicit(String[] fields){
StringBuilder result=new StringBuilder();
for (int i = 0; i < fields.length; i++) {
result.append(fields[i]);
}
return result.toString();
}

再次运行javap -c StringTest:

 public java.lang.String implicit(java.lang.String[]);
    Code:
       0: ldc           #11                 // String
       2: astore_2
       3: iconst_0
       4: istore_3
       5: iload_3
       6: aload_1
       7: arraylength
       8: if_icmpge     38(对堆栈中的操作数进行“大于或等于的整数比较运算”循环结束时跳到38行
      11: new           #3                  // class java/lang/StringBuilder
      14: dup
      15: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      18: aload_2
      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: aload_1
      23: iload_3
      24: aaload
      25: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: astore_2
      32: iinc          3, 1
      35: goto          5  (返回循环体的起始点 第五行
      38: aload_2
      39: areturn

从循环开始到结束,可以看到StringBuilder是在循环体内构造的,这意味着没循环一次就会创建一个新的StringBuilder对象


public java.lang.String expicit(java.lang.String[]);
    Code:
       0: new           #3                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
       7: astore_2
       8: iconst_0
       9: istore_3
      10: iload_3
      11: aload_1
      12: arraylength
      13: if_icmpge     30
      16: aload_2
      17: aload_1
      18: iload_3
      19: aaload
      20: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: pop
      24: iinc          3, 1
      27: goto          10
      30: aload_2
      31: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: areturn
}

而第二个方法中可以看到,代码更简短,并且只生成了一个StringBuilder对象。显式的创建StringBuilder还允许预先指定大小,如果是预先知道字符串的大小大概有多少,那就可以预先指定其大小可以避免多次重新分配缓冲


因此,如果为一个类编写toString()方法时,如果字符串比较简单就可以信赖编辑器,如果是需要循环,那么还是最好自己创建一个StringBuilder对象。

如果判断不来哪个更好,随时可以用javap来分析你的程序。

StringBuilder提供的方法:

insert()

repleace()

substring()

reverse()

append()

toString()

delete()

StringBuilder是java SE5开始引入的,之前是StringBuffer,后者是线程安全的。

(看书时的记录)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值