1 String是不可变的
这个结论当然是正确的,通过JDK文档,发现每一个看似会修改String的方法,其实都是在底部创建了一个新的String对象,进行返回,把地址值赋值给变量,原来的String对象是没有发生变化的,当然这和操作普通的实体对象还是不一样的【别的一般对象是修改自己,把自己返回】,如果看String源码的话,底层是通过一个Final修饰的char数组维护的(final修饰的数组内容是可以变的,地址值不变)
【注:你真的想改变字符串可以通过暴力反射】
Stirng源码:变量定义
/** The value is used for character storage. */
private final char value[];
String源码:replace方法部分源码为例
if (i < len) {
//重新定义了一个长度一样的数组,将原来数组的内容复制过去
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
//替换掉字符(部分省略)
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
//返回的是新的字符数组
return new String(buf, true);
}
2 字面值创建对象和new创建的区别
2.1 直接创建
String s = "HelloWorld";
创建之后是在方法区的常量池,只开辟一块内存,每当下一次对不同的对象进行直接赋值的时候会直接利用池中原有的匿名对象
2.2 构造方法创建
Stirng s = new Stirng("Hello World");
创建之后保存在堆内存中,这种方式和普通对象的创建方式一样,用法也一样,而且不能够自动入池,需要通过public String intern();方法进行手工入池,开发时不会使用此方法
3 字符串“+”拼接和StringBuilder
这部分内容是参考了《JAVA编程思想》第13章,详细内容请自行翻阅
也许大家都告诉你字符串是不可变的,告诉你要使用StringBuilder去优化,当然这句话是没有错的,可有些方面我觉得我们需要知道!
String s = "abc" + "mango" + "def";
按照这个例子也许我们会想,会生成多余的两个Stirng对象,但事实也并非这样,如果使用 javap -c Concatenation反编译我们会发现,在底部编译器自动生成了StringBuilder对象去帮助我们优化性能,但是编译器的优化程度有限,如果使用"+"循环拼接,就会创建多个StringBuilder对象,即使你创建了StringBuilder对像,当使用append(a+“:”+c)时a,c为变量,编译器也会创建一个StringBuilder对象去处理中间的字符串
所以简单的拼接可以使用“+”,当进行大量的循环拼接时,也并非手动创建一个StirngBuilder对象就万事大吉了,要多加注意,不清楚可以反编译一哈。
关于常量池以及内存等知识,下面准备一篇博客来说明
参考博客:https://www.cnblogs.com/zhangyinhua/p/7689974.html
参考教材:《JAVA编程思想》