NO.5 不平凡的螺丝钉:String兄弟连 | Java敲黑板系列

开场白

老铁:最近两天双11电商购物节闹得沸沸扬扬,卖家使出全身解数搞促销,买家把积攒了一年的购物热情也在这一天尽情释放,共同创造着一年又一年新的奇迹,不断对当前世界上最强计算力、运输力等发起挑战。可以这么说,中国电子商务的发达程度不逊于任何一个国家,在科技领域能有这样让人扬眉吐气的事情,想想真是提劲。

类似于高楼大厦必然是由简单到一砖一瓦一螺钉构成的,庞大而复杂的电商系统也是由一行行代码构成的。据了解,承载着某巴、某东万亿次访问的电商后台大部分都是由Java语言编写。Java语言本身就是一件复杂的技术,今天我们就谈谈该程序语言中使用最为频繁的语言特性——字符串。

Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类——String。每个用双引号括起来的字符串都是String类的一个对象实例。由于在系统开发过程中String使用的非常频繁,标准Java类库还提供了StringBuffer、StringBuilder等类,方便用户开发使用。如果对全世界的Java源代码中类名关键字的出现次数进行统计的话,我想如果String的排序应该是数一数二了。如此频繁的身影出现在我们所编写的源代码中,名副其实的可被称为Java大厦的“螺丝钉”。但是,我们真的很了解这位经常见面的兄弟吗?

为此,今天我们非常荣幸请来了“String”、“StringBuffer”、“StringBuilder”组成的兄弟连来到我们的第五期“Java敲黑板系列”,有请!

String

String类是不可修改的类,也就是创建了String对象后就不能修改了,比如新建了一个“123”的String对象,那么在内存中都会是“123”这样具有固定值的一个对象,不能被修改;此外,也可通过String提供的方法来尝试修改,返回值要么是创建一个新的字符串对象;要么返回自己。

由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池,其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。

敲黑板:

但是,请注意:通过new方法创建的String对象是不检查字符串池的,也不会把对象放入池中。上述原则只适用于通过直接量给String对象引用赋值的情况。

String str1 = "123"; //通过直接量赋值方式
String str2 = new String("123");//通过new方式赋值方式
String str3 = "12" + "3";//通过直接量赋值方式
String str4 = "1"+"2"+"3";//通过直接量赋值方式

System.out.println(str1 == str2);//false:不符合常量池规则
System.out.println(str1 == str3);//true:符合常量池规则
System.out.println(str1 == str4);//true:符合常量池规则
System.out.println(str2 == str4);//false:不符合常量池规则
System.out.println(str4 == str4.substring(0));//true:调用方法后字符串的值没有发生变化,直接返回了自身
System.out.println(str4 == str4.substring(1));//false:调用方法后字符串的值得到了修改,创建了新的对象

StringBuffer

StringBuffer是一个可变字符序列,在内存中的存储方式与String相同,都是以一个有序的字符序列(char类型的数组)进行存储,不同点是StringBuffer对象的值是可以改变的,并且值改变以后,对象引用不会发生改变。

String s1 = "1";
String s2 = s1 + "23";//按照规则,会创建新的对象,返回新的对象引用;并将新的对象放入池中
System.out.println(s1 == s2);//false:s1与s2是两个不同的对象引用

StringBuffer sb = new StringBuffer("1");
StringBuffer sb1=sb.append("23");//对于StringBuffer值得到了修改,但是引用地址并不会发生变化
System.out.println(sb == sb1);//true:值不同,但是引用地址不变

StringBuilder

StringBuilder与StirngBuffer基本相同,都是可变字符序列,此处不再繁述。唯一需要注意的是:StringBuffer是线程安全的,但是StringBuilder是线程不安全的。可参看Java标准类库的源代码,StringBuffer类中方法定义前面都会有synchronize关键字。为此,StringBuffer的性能要远低于StringBuilder。

小结

敲黑板,画重点:

  1. String提供了字符串常量池机制,其运行机理是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。通过new方法创建的String对象是不检查字符串池的,也不会把对象放入池中。上述原则只适用于通过直接量给String对象引用赋值的情况。
  2. 在字符串内容不经常发生变化的业务场景优先使用String类。例如:常量声明、少量的字符串拼接操作等。如果有大量的字符串内容拼接,避免使用String与String之间的“+”操作,因为这样会产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。
  3. 在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程环境下,建议使用StringBuffer,例如XML解析、HTTP参数解析与封装。
  4. 在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程环境下,建议使用StringBuilder,例如SQL语句拼装、JSON封装等。

转载自公众号:代码荣耀
图1

猜你喜欢

转载自blog.csdn.net/maijia0754/article/details/80568042