1. immutable不可改变特性
String类对象都是不可修改的。如果我们去查阅JDK文档关于String类的信息,我们将发现所有看起来修改了String内容的方法其实是返回了一个全新的对象包含了这部分修改内容。原始的String字符串依然保持原封不动,未做过任何修改。这种设定保证了的代码很容易写,而且易于被人理解。
Objects of the String class are immutable. If you examine the JDK documentation for the String class, you’ll see that every method in the class that appears to modify a String actually creates and returns a brand new String object containing the modification. The original String is left untouched.
This is an important guarantee, since it makes code easier to write and understand.
2. String的’+’ & ‘+=’
因为String类型的对象是read-only的,所以在字符串引用上所做的修改不可能会影响其它的引用。
但是String的这种imutable特性也又一些效率上的代价存在。
另:’+’&’+=’是java语言中唯二被重载的操作符号,Java语言不允许程序猿重载任何其他的操作符。
所以一般在做对于String的修改操作时,一般会用StringBuilder作中间处理,减少对象的连续创建和释放带来的系统性能开销。
package com.fqy.blog;
import java.util.Random;
public class StringBuilderDemo {
private Random random = new Random();
public String toString() {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < 10; i++) {
sb.append(random.nextInt(100));
sb.append(", ");
}
/*
* StringBuilder.delete(int start, int end) start inclusive, and end
* exclusive
*/
sb.delete(sb.length() - 2, sb.length());
sb.append("]");
// return the number of unicode units in the string.
System.out.println(sb.length());
// System.out.println(sb.toString().length());
return sb.toString();
}
public static void main(String[] args) {
StringBuilderDemo sbd = new StringBuilderDemo();
System.out.println(sbd);
}
}
//Running result:
39
[32, 4, 54, 83, 43, 16, 35, 52, 64, 31]
3. 关于toString()方法的一个栈溢出的问题
当编译器看到一个String对象,其后跟着的是一个非String类型的东西时,它会试图将其解析成一个String类型的对象。问题出现了,它会不断地调用自身,直到栈空间耗尽。控制台被不断的栈溢出所淹没,不知所措。
解决方式之一是:调用父类的方法super.toString()方法。
package com.fqy.blog;
public class StackFlowDemo {
@Override
public String toString() {
// This will cause infinite loop here this way.
return "Infinite Recursion address: " + this + "\n";
// This will work.
// return super.toString();
}
public static void main(String[] args) {
System.out.println(new StackFlowDemo());
}
}
//Running result:
Exception in thread "main" java.lang.StackOverflowError
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at java.lang.StringBuilder.<init>(StringBuilder.java:113)
at com.fqy.blog.StackFlowDemo.toString(StackFlowDemo.java:7)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at com.fqy.blog.StackFlowDemo.toString(StackFlowDemo.java:7)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at com.fqy.blog.StackFlowDemo.toString(StackFlowDemo.java:7)
at java.lang.String.valueOf(String.java:2994)
...
4. 关于String对象的内存存储问题
这里展示几个常见方法:toCharArray()/valueOf()/intern().
其中关于intern() 方法存在的意义的问题,stackoverflow上有详细问题,具体参见这里和这里。
Q:What is String interning?–什么是intern()方法?
A:Basically doing String.intern() on a series of strings will ensure that all strings having same contents share same memory. 一般说来,我们调用intern()方法,将会使得有相同内容的String对象在内存中只有一份存储。
这样做的好处是降低了程序对于内存的需求;但问题在于这部分缓存是被JVM的permanent memory区所维护的,永久区内存大小通常比heap区内存要小得多,所以如果不是对象特别多的话,不要使用intern()方法。
Q:到底我们应该什么时候使用intern()方法呢?
A:String.intern()方法在该String对象在String pool中被发现存在时,返回该对象的引用;否则则会在String pool中插入一个新对象,并返回新对象的引用。
Q:intern在String.intern()的应用?
A:这里分为2种情形。1.java自动将字符串字面值sting literals转换为intern的,比如String str1 = “this is literal str”;。这意味着,==对于这类的String类型数据就像基本数据类型一样比如int . 2.对于使用new String()方法创建的String对象,是需要使用intern()方法保证其内存空间的唯一性的。
package com.fqy.blog;
public class StrOpr {
public static void main(String[] args) {
int num = 12345;
String str = "fqyuan";
String str1 = new String("fqyuan");
String str2 = "fqyuan";
// 1.String.toCharArray(), return character array of the string
char[] arr = str.toCharArray();
// 2. static method, convert the input to String.
String intVal = String.valueOf(num);
// 3.This is a special case that need to be taken care of.
String inString = str.intern();
System.out.println(arr);
System.out.println(intVal);
System.out.println(inString);
if (str == str1)
System.out.println("str == str1");
if (str == str2)
System.out.println("str == str2");
if (str == str1.intern())
System.out.println("str == str2.intern()");
//an equality check on the contents of the two Strings.
if (str.equals(str1))
System.out.println("str equals str1");
}
}
//Running result:
fqyuan
12345
fqyuan
str == str2
str == str2.intern()
str equals str1