1. 如何构建超大字符串?
public class Main {
public static void main(String[] args) {
String str= "ab" + "cd" + "ef";
System.out.println(str == "abcdef"); // true
}
}
上述代码会不会生成String对象 ab,然后生成String对象 abcd ,然后再生成String对象abcdef呢?其实不是。通过反编译可以看到,上述代码只生成了一个对象即String对象abcdef。
基于上述分析
通过for循环生成大String
public static void main(String[] args) {
String str = "abcdef";
for (int i = 0; i < 1000; i++) {
str = str + i;
}
}
观察反编译代码
可以看出上述代码Jvm已经做了优化,内部通过StringBuilder来优化了。但是通过上图可以看到1000次循环,内部创建了1000个StringBuilder对象,但后多个StringBuilder对象append构成最后的结果。这里存在的问题不言而喻了。
最佳生成大字符串的方式
public static void main(String[] args) {
StringBuilder str = new StringBuilder("abcdef");
for (int i = 0; i < 1000; i++) {
str.append(i);
}
}
观察反编译结果只用一个StringBuilder对象即可。时空效率势必提升。
2、如何使用 String.intern 节省内存?
public static void main(String[] args) {
// case1:
String a1 = new String("abc");
String b1 = new String("abc");
if (a1 == b1) {
System.out.println("a1 == b1");
} else {
System.out.println("a != b1");
}
// case2:
String a2 = new String("abc").intern();
String b2 = new String("abc").intern();
if (a2 == b2) {
System.out.println("a2 == b2");
} else {
System.out.println("a2 != b2");
}
}
a != b1
a2 == b2
case1: 两次new堆中创建2个对象 == 比较2个对象的引用地址,不相等则返回 a != b1
case2: 实际上是将字符串变量从存储堆中转移的常量池中,这样b2对应在创建的时候会判断常量池中是否会存在abc字符串常量,存在则直接拿来主义,这样可以少创建一个对象节省内存空间。
3、 如何使用字符串的分割方法?
String.split() 方法使用正则表达式来实现强大的分割能力,但是正则表达式的性能比较不稳定的,使用的不好会引起回溯问题,导致 CPU 使用率居高不下。应慎重使用 String.split() 方法,如果业务允许可以用 String.indexOf() 方法代替 String.split()方法完成字符串的分割。