第5讲 | String、StringBuffer、StringBuilder有什么区别?
该思维导图由 AI 生成,仅供参考
典型回答
考点分析
- 深入了解
- 翻译
- 解释
- 总结
Java中的字符串类包括String、StringBuffer和StringBuilder,它们在设计和使用上有着明显的区别。String是不可变的,任何对它的操作都会生成新的String对象,因此在频繁操作字符串时可能会产生大量临时对象。为了解决这个问题,Java提供了StringBuffer和StringBuilder,它们都是可变的,允许在已有序列的末尾或指定位置添加字符串,但StringBuffer是线程安全的,而StringBuilder则不是。因此,在大多数情况下,推荐使用StringBuilder进行字符串拼接。 理解这些字符串类的设计和实现对于编写高质量的代码至关重要。除了上述基本区别,文章还提到了一些可能的面试考点,如线程安全设计与实现、JVM对象缓存机制、Java代码优化技巧以及String类的演进。这些内容对于深入理解Java字符串类及其在实际开发中的应用都具有重要意义。 文章还介绍了字符串缓存和字符串自身的演化,包括intern()方法、字符串缓存的位置变化以及Java 9中引入的Compact Strings的设计。这些内容展示了Java平台工程师和科学家在字符串优化方面的努力,以及Java字符串类的不断演进和优化。 总之,本文通过简洁明了的方式介绍了Java中String、StringBuffer和StringBuilder的区别,以及相关的技术考点,对于想要快速了解这些内容的读者来说,是一份很有价值的概览。文章内容涵盖了Java字符串类的基本知识和技术特点,对于Java开发者和对字符串优化感兴趣的读者都具有参考价值。
《Java 核心技术面试精讲》,新⼈⾸单¥59
全部留言(143)
- 最新
- 精选
- Bin置顶jdk1.8中,string是标准的不可变类,但其hash值没有用final修饰,其hash值计算是在第一次调用hashcode方法时计算,但方法没有加锁,变量也没用volatile关键字修饰就无法保证其可见性。当有多个线程调用的时候,hash值可能会被计算多次,虽然结果是一样的,但jdk的作者为什么不将其优化一下呢?
作者回复: 这些“优化”在通用场景可能变成持续的成本,volatile read是有明显开销的; 如果冲突并不多见,read才是更普遍的,简单的cache是更高效的
2018-05-161287 - 公号-技术夜未眠今日String/StringBuffer/StringBuilder心得: 1 String (1) String的创建机理 由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池。其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。但是,通过new方法创建的String对象是不检查字符串池的,而是直接在堆区或栈区创建一个新的对象,也不会把对象放入池中。上述原则只适用于通过直接量给String对象引用赋值的情况。 举例:String str1 = "123"; //通过直接量赋值方式,放入字符串常量池 String str2 = new String(“123”);//通过new方式赋值方式,不放入字符串常量池 注意:String提供了inter()方法。调用该方法时,如果常量池中包括了一个等于此String对象的字符串(由equals方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并且返回此池中对象的引用。 (2) String的特性 [A] 不可变。是指String对象一旦生成,则不能再对它进行改变。不可变的主要作用在于当一个对象需要被多线程共享,并且访问频繁时,可以省略同步和锁等待的时间,从而大幅度提高系统性能。不可变模式是一个可以提高多线程程序的性能,降低多线程程序复杂度的设计模式。 [B] 针对常量池的优化。当2个String对象拥有相同的值时,他们只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大幅度节省内存空间。 2 StringBuffer/StringBuilder StringBuffer和StringBuilder都实现了AbstractStringBuilder抽象类,拥有几乎一致对外提供的调用接口;其底层在内存中的存储方式与String相同,都是以一个有序的字符序列(char类型的数组)进行存储,不同点是StringBuffer/StringBuilder对象的值是可以改变的,并且值改变以后,对象引用不会发生改变;两者对象在构造过程中,首先按照默认大小申请一个字符数组,由于会不断加入新数据,当超过默认大小后,会创建一个更大的数组,并将原先的数组内容复制过来,再丢弃旧的数组。因此,对于较大对象的扩容会涉及大量的内存复制操作,如果能够预先评估大小,可提升性能。 唯一需要注意的是:StringBuffer是线程安全的,但是StringBuilder是线程不安全的。可参看Java标准类库的源代码,StringBuffer类中方法定义前面都会有synchronize关键字。为此,StringBuffer的性能要远低于StringBuilder。 3 应用场景 [A]在字符串内容不经常发生变化的业务场景优先使用String类。例如:常量声明、少量的字符串拼接操作等。如果有大量的字符串内容拼接,避免使用String与String之间的“+”操作,因为这样会产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。 [B]在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程环境下,建议使用StringBuffer,例如XML解析、HTTP参数解析与封装。 [C]在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程环境下,建议使用StringBuilder,例如SQL语句拼装、JSON封装等。
作者回复: 很到位
2018-05-1518633 - 愉悦在花香的日子里getBytes和String相关的转换时根据业务需要建议指定编码方式,如果不指定则看看JVM参数里有没有指定file.encoding参数,如果JVM没有指定,那使用的默认编码就是运行的操作系统环境的编码了,那这个编码就变得不确定了。常见的编码iso8859-1是单字节编码,UTF-8是变长的编码。
作者回复: 不错,莫依赖于不确定因素
2018-05-15254 - VanString myStr = "aa" +"bb" + "cc" +"dd";反编译后并不会用到StringBuilder,老师反编译结果中出现StringBuilder是因为输出中拼接了字符串System.out.println("My String:" + myStr);
作者回复: 嗯,文中的例子有歧义,确实欠考虑
2018-09-1939 - DoctorDengString s = new String("1"); s.intern(); String s2 = "1"; System.out.println(s == s2); String s3 = new String("1") + new String("1"); s3.intern(); String s4 = "11"; System.out.println(s3 == s4); 这道面试题不错,即考察了 intern() 的用法,也考察了字符串常量池在不同版本 JDK 的实际存储,具体可以看看美团博客:https://tech.meituan.com/in_depth_understanding_string_intern.html,
作者回复: 思路比结论更有价值
2018-09-21832 - Jerry银银特别喜欢这句话:“仅仅是字符串一个实现,就需要 Java 平台工程师和科学家付出如此大且默默无闻的努力,我们得到的很多便利都是来源于此。” 我想说,同学们,写代码的时候记得感恩哦😄 对于字符串的研究,我觉得能很好的理解计算机的本质和训练计算机思维,提升自己解决问题的能力。 小小的字符串有着诸多巨人的影子
作者回复: 非常感谢
2018-05-1528 - 肖一林这篇文章写的不错,由浅入深,把来龙去脉写清楚了
作者回复: 谢谢认可
2018-05-1514 - 好运来老师,可以讲解这一句话的具体含义吗,谢谢! 你可以思考下,原来 char 数组的实现,字符串的最大长度就是数组本身的长度限制,但是替换成 byte 数组,同样数组长度下,存储能力是退化了一倍的!还好这是存在于理论中的极限,还没有发现现实应用受此影响。
作者回复: 已回复,一个char两个byte,注意下各个类型宽度
2018-05-159 - ©®String s2=new String("AB"),,如果,常量池中没有AB,那么会不会去常量池创建,望解答
作者回复: new只是创建新的;另外,有没有想过怎么通过一段程序证明?这样更有助于理解
2018-05-237 - So Leung经过验证new String时,不会再常量池中创建对象。
作者回复: 嗯,重要的不是结论,而是如何得到结论
2018-05-2435