在我们编程的过程中,发现字符串做操是很常见的行为,最近在研读《Java编程思想》,结合一下自己所学总结一下Java中的字符串。
让我们看一下Java中最常见的几个与字符串相关的类的UML图:
其中String是不可变的(only read),所谓是不可变是因为每一次改变的操作都回新new一个对象
看java源码:
public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = value.length - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);//如果beginIndex == 0就返回自己,不然就new一个新对象 }
</pre><pre name="code" class="java">public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true);//new一个新对象 }
也看一下java源码:
public AbstractStringBuilder deleteCharAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); System.arraycopy(value, index+1, value, index, count-index-1); count--; return this;//返回的是自己 }有一点我这里需要特别说明的是String中的运算符重载 "+"和"+=",java中仅有的重载的运算符,java本身不支持运算符重载。
例如:String str = "a" + "b" + "c" +10;
问这里面产生了多少字符串呢?
我记不清在哪里看的了,说每次+就会产生新的String对象,昨天看《Java编程思想》时,才知道自己错,JVM知道String字符串连接效率低下,对它做了优化!
请看代码!
public class Main { public static void main(String[] args) { String str = "a"; String string = "b" + str + "c" + 47; System.out.println(string); } }经过 javac Main.java
javap -c Main之后
public class Main { public Main(); 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 a 2: astore_1 3: <span style="font-size:24px;color:#ff6600;">new #3 // class java/lang/StringBuilder</span> 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 10: ldc #5 // String b 12: invokevirtual #6 // Method java/lang/StringBuilder.<span style="font-size:24px;color:#330099;">append</span>:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: aload_1 16: invokevirtual #6 // Method java/lang/StringBuilder.<span style="font-size:24px;color:#330099;">append</span>:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: ldc #7 // String c 21: invokevirtual #6 // Method java/lang/StringBuilder.<span style="font-size:24px;color:#330099;">append</span>:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: bipush 47 26: invokevirtual #8 // Method java/lang/StringBuilder.<span style="font-size:24px;color:#330099;">append</span>:(I)Ljava/lang/StringBuilder; 29: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 32: astore_2 33: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream; 36: aload_2 37: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 40: return }我们可以看到是new了一个StringBuilder来优化String的"+"操作,并调用append来连接字符串
要注意:
1.一次String的"+"的操作和StringBuilder操作在JVM是一样的,但此在循环中String的连接时创建多个StringBuilder,而StringBuilder的append只创建一次.
2.不要这样使用StringBuilderd的append()方法:sb.append(str1 + "-"+ str2);会令创建对象
String,StringBuilder和StringBuffer上的操作,帮助文档和源码中写的很清楚,可以自行查阅!
字符串中的操作有一个容易被我们忽略的地方:toString()
无意识的递归:
请看下面代码:
<span style="white-space:pre"> </span>public class Main { public static void main(String[] args) { Main main = new Main(); System.out.println(main); } public String toString() { return "Main address: " + this + "\n";// 这里的this与字符串连接会先调用toString(),就造成了递归,然后就StackOverFlow // super.toString() 修改方法 } }