剖析java中的String之__拼接

String类中的面试常考点 String类 常用方法介绍 String类是Java最常用的API,它包含了大量处理字符串的方法,比较常用的有: char charAt(int index):返回指定索引处的字符; String substring(int beginIndex, int endIndex):从此字符串中截取出一部分子字符串; String[] split(String regex):以指定的规则将此字符串分割成数组; String trim():删除字符串前导和后置的空格; int indexOf( 阅读详情

绝对原创, 转载时请标明下出处, http://blog.youkuaiyun.com/izard999/article/details/6708433谢谢!


网上剖析String的不少,关于其他的String的知识我就不累赘去说了!

本文只解释下我在面试中遇到的String拼接的问题以及最近看到了网上的一道机试题跟这个有关系, 所以就想把自己对String拼接的理解分享给大家! 

去华为面试的时候, 第一笔试题就让我费神去想了, 回来在机子上运行结果, 发现自己当时答错了, 于是就狠下心来花了点时间研究这个:

String s = null;
s += "abc";
System.out.println(s);

答案是nullabc!

就这三行代码, 我问了不下于50个人, 有资深的人也有新手的, 在不运行的情况下全答错了。!  可见现在学java的人有很多人都是速成的,而且这种原理级而又看似不怎么实用的东西几乎没什么人去研究, 但是后面说的机试如果能知道String拼接的原理的话。将很容易就解决!

很早的时候我就知道String拼接中间会产生StringBuilder对象(JDK1.5之前产生StringBuffer),但是当时也没有去深究内部, 导致在华为笔试此题就错了!

运行时, 两个字符串str1, str2的拼接首先会调用 String.valueOf(obj),这个Obj为str1,而String.valueOf(Obj)中的实现是return obj == null ? "null" : obj.toString(), 然后产生StringBuilder, 调用的StringBuilder(str1)构造方法, 把StringBuilder初始化,长度为str1.length()+16,并且调用append(str1)! 接下来调用StringBuilder.append(str2), 把第二个字符串拼接进去, 然后调用StringBuilder.toString返回结果!

所以那道题答案的由来就是StringBuilder.append("null").append("abc").toString();

大家看了我以上的分析以后, 再碰到诸如此类的面试题应该不会再出错了!


那么了解String拼接有什么用呢?

在做多线程的时候, 往往会用到一个同步监视器对象去同步一个代码块中的代码synchronized(Obj),   对同一个对象才会互斥,不是同一个对象就不会互斥!

这里有个机试题,

现有程序同时启动了4个线程去调用TestDo.doSome(key, value)方法,由于TestDo.doSome(key, value)方法内的代码是先暂停1秒,然后再输出以秒为单位的当前时间值,所以,会打印出4个相同的时间值,如下所示:
  4:4:1258199615
  1:1:1258199615
  3:3:1258199615
  1:2:1258199615
        请修改代码,如果有几个线程调用TestDo.doSome(key, value)方法时,传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果,即当有两个线程的key都是"1"时,它们中的一个要比另外其他线程晚1秒输出结果,如下所示:
  4:4:1258199615
  1:1:1258199615
  3:3:1258199615
  1:2:1258199616
   总之,当每个线程中指定的key相等时,这些相等key的线程应每隔一秒依次输出时间值(要用互斥),如果key不同,则并行执行(相互之间不互斥)。原始代码如下:

  1. package syn;  
  2.   
  3. //不能改动此Test类      
  4. public class Test extends Thread{  
  5.       
  6.     private TestDo testDo;  
  7.     private String key;  
  8.     private String value;  
  9.       
  10.     public Test(String key,String key2,String value){  
  11.         this.testDo = TestDo.getInstance();  
  12.         /*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象, 
  13.         以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/  
  14.         this.key = key+key2;   
  15.         this.value = value;  
  16.     }  
  17.   
  18.   
  19.     public static void main(String[] args) throws InterruptedException{  
  20.         Test a = new Test("1","","1");  
  21.         Test b = new Test("1","","2");  
  22.         Test c = new Test("3","","3");  
  23.         Test d = new Test("4","","4");  
  24.         System.out.println("begin:"+(System.currentTimeMillis()/1000));  
  25.         a.start();  
  26.         b.start();  
  27.         c.start();  
  28.         d.start();  
  29.     }  
  30.       
  31.     public void run(){  
  32.         testDo.doSome(key, value);  
  33.     }  
  34. }  
  35.   
  36. class TestDo {  
  37.   
  38.     private TestDo() {}  
  39.     private static TestDo _instance = new TestDo();   
  40.     public static TestDo getInstance() {  
  41.         return _instance;  
  42.     }  
  43.   
  44.     public void doSome(Object key, String value) {  
  45.   
  46.         // 以大括号内的是需要局部同步的代码,不能改动!  
  47.         {  
  48.             try {  
  49.                 Thread.sleep(1000);  
  50.                 System.out.println(key+":"+value + ":"  
  51.                         + (System.currentTimeMillis() / 1000));  
  52.             } catch (InterruptedException e) {  
  53.                 e.printStackTrace();  
  54.             }  
  55.         }  
  56.     }  
  57.   
  58. } 
此题解题的思路有很多种,不可或缺的步骤就是在doSome方法内部用synchronized(o)把那个写了注释的代码块同步, 有些人肯定会说:

我直接synchronized(key),不就完了么.?  这类人肯定是新手级别的了!

上面说了,synchronized(Obj),   对同一个对象才会互斥,不是同一个对象就不会互斥! 大家请看下Test类中的构造方法里面对key做了什么处理?

this.key = key + key2;

关于字符串的拼接,  如果是两个常量的拼接, 那么你无论拼接多少下都是同一个对象,  这个是编译时 编译器自动去优化的(想知道具体原理的自己去网上搜下).

String a = "a" + "b";
String b = "a" + "b";
System.out.println(a == b);

这段代码输出true没有问题

但是一旦涉及到变量了, 我在上面标红加粗的运行时,    此时拼接字符串就会产生StringBuilder,  然而拼接完返回的字符串是怎么返回的呢?

在StringBuilder.toString()中的实现是new String(char value[], int offset, int count), 既然是创建String返回的, 那么调用一次toString,就是一个不同的对象

String a = "a";
String b = "b";
String s1 = a + b;
String s2 = a + b;
System.out.println(s1 == s2);
这个输出就是false!


所以在那道机试题中, 就不能直接用synchronized(key)去同步了,  如果你完完全全很耐心的看完本文, 那么应该知道如何用synchronized(key)同步那段代码了!

不错, 就是修改Test构造方法中的 this.key = key + key2;为this.key = key;

因为字符串不涉及到拼接的时候, 只要不new, 多少都是指向同一个对象!

当然这道多线程的题你也可以把那个key丢到集合里面去,用集合去的contains(obj)去判断,如果集合中存在, 就取集合中的, 否则往集合中添加,但是记住一定要使用并发包下面的集合, 否则可能会抛出ConcurrentModificationException

【Java踩坑笔记】【基础语法篇】04_String+背后发生了什么?别让拼接拖垮性能 循环里用。 阅读详情

相关推荐

内存优化--LOGBACK导致内存告警

一.故事背景 由于开辟新市场需要,开发了新的项部署在海外平台,其中最消耗内存的功能是消费kafka消息(最开始预计一天有1千万的量),部署完之后运行一段时间发现出现内存告警问题。 二.分析问题 出现内存告警,(新项目是低配置机器 2C4G * 2台)第一个念头是去查看堆空间设置的情况,看到jvm启动命令中堆空间都是直接指定大小,说明问题不是出在堆空间 -Xmx3g -Xms3g 先不管这些,去查看总的内存使用情况,发现总的内存空间使用将近有92% = 3.68G,那么这多出来使用的0.6

qq_33199919的博客 6052

Java中常见字符串拼接九种方式,总有一款你喜欢!

在 Java 编程中,字符串拼接是一项非常基础的操作,它涉及到了很多日常开发工作中常见的场景,例如拼接 SQL 语句、构建 HTTP 请求参数等等。因此,对于掌握好字符串拼接技巧不仅有助于提高代码效率,而且能够避免一些潜在的性能问题。下面我们就来列举出来几种方式,搭配例子!在 Java 中,字符串拼接是很常见的操作。不同的场景需要选择合适的字符串拼接方式,以达到更高的效率和更好的代码可读性。理解字符串拼接的不同方式,选择适合当前场景的方法能够提高代码效率、可读性和可维护性。

小王博客基地 2万+

时空双重机器学习在环境政策评估中的创新应用

因果推断是数据分析中的核心问题,特别是在环境政策评估领域。传统方法如差异分析法(DID)在处理时空维度上的复杂相关性时存在局限。机器学习技术,特别是双重机器学习(DML),通过分阶段建模有效解决了混杂变量问题。结合贝叶斯加性回归树(BART)的灵活建模能力,可以更准确地捕捉空间和时间模式。这种时空双重机器学习(ST-DML)方法在柬埔寨森林砍伐案例中表现出色,通过Wendland基函数有效处理了空间自相关问题。该技术框架不仅适用于环境政策评估,还可扩展至空气质量、水资源管理等其他领域,为政策制定提供更精准的

weixin_28685045的博客 345

Java中字符串常见的拼接方式

先有StringBuffer后有StringBuilder,两者就像是孪生双胞胎,该有的都有,只不过大哥StringBuffer,大部分方法都经过synchronized修饰,所以StringBuffer是线程安全的,但是它效率就相对StringBuilder较低。实战项目中,我们处理字符串的时候,经常会用到这个类.org.apache.commons.lang3.StringUtils包下,该方法更善于拼接数组中的字符串,并且不用担心NullPointerException。...

山路曲折盘旋,但毕竟朝着顶峰延伸 3万+

ChatGPT Web转API工具:原理、部署与集成实战

在AI应用开发中,API(应用程序编程接口)是实现系统间通信和数据交换的核心技术,它通过标准化的请求响应机制,将复杂功能封装为可编程的服务。其工作原理基于HTTP协议,通过定义清晰的端点、方法和数据格式,使不同平台的应用能够高效集成AI能力。这一技术价值在于极大降低了开发门槛,促进了自动化流程和智能功能的快速落地,广泛应用于智能客服、内容生成和创意辅助等场景。本文聚焦于如何通过浏览器自动化技术,将ChatGPT的Web界面能力转化为标准API服务,其中涉及Playwright无头浏览器操作和会话Cookie

weixin_42533910的博客 1766

【吐血整理-历时两个月,长达万字】FDTD Solutions学习笔记

原教学视频来自于Ansys-Lumerical官方的FDTD100,所看视频来自B站大佬UP主 【Nestor_呐等】 的幸苦翻译,本文内容粘贴自我个人在学习FDTD100时,通过字幕和一些个人理解总结的一份word。整理不易,强烈建议收藏!...

weixin_45719141的博客 10万+

JAVA字符串拼接的方式有哪些?

JAVA字符串拼接的方式有哪些?

qq_52897257的博客 3689

【08】C#实战篇——C#调用C++ 动态库dll,报错 “无法加载DLL“xxx.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。”

摘要: 本文详细分析了C#调用C++封装的DLL时出现“无法加载DLL”错误的排查与解决方法。通过案例演示,列举了常见原因(如平台不匹配、路径错误、依赖缺失等),并重点介绍了使用VS的dumpbin工具检测DLL依赖项的方法。最终定位问题为缺失依赖的LineApi.dll和opencv_world455d.dll,将其放入C#的exe目录后解决。文章还对比了C++与C#的报错差异,提供了通用解决方案,包括检查运行时库、环境变量等,帮助开发者高效解决类似问题。 关键词: C#调用C++ DLL、dumpbin

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 2099

关于 Java 字符串拼接的几种方式以及性能比较

一、字符串拼接 字符串拼接是我们在Java代码中比较经常要做的事情,就是把多个字符串拼接到一起。 我们都知道,String 是 Java 中一个不可变的类,所以他一旦被实例化就无法被修改。 不可变类的实例一旦创建,其成员变量的值就不能被修改。这样设计有很多好处,比如可以缓存 hashcode、使用更加便利以及更加安全等。 但是,既然字符串是不可变的,那么字符串拼接又是怎么回事呢? 1...

游戏建模零基础入门教程 4862

C# 上位机程序中的数据采集与存储技术:从采集到持久化的完整解决方案

本文系统讲解C#上位机程序如何实现设备数据采集与持久化。主要内容包括:1)多种数据采集方式(串口通信、Modbus、OPC等)及代码示例;2)详细对比不同存储技术(CSV、SQLite、关系型数据库等)的优缺点;3)提供SQLite等存储实现代码;4)推荐分层系统架构(采集-缓存-存储-可视化);5)性能优化建议(多线程采集、异步存储、批量写入等)。文章强调应根据项目需求选择合适的技术方案,构建高效稳定的数据采集存储闭环系统。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1025

rk3568 点亮双LVDS 屏

承接文章《rk3568点亮LCD(lvds)》中仅仅只能使用亮单LVDS;经过厂商的努力,陆续发布新补丁。目前支持双lvds显示,缺憾是需要自己额外移植相关补丁。受限于通信频率和VOP编码能力,支持最大分辨仍然是1920x1080、60fps。

weixin_35723192的博客 3008

String字符串拼接 底层原理

String字符串拼接的原理, 如String s = "abd" + "cff"

灿的博客 526

2026年全国青少年信息素养大赛复赛真题(算法应用主题赛C++初中组:带解析)(7月4日试卷一)【文末附答案和解析】

2026年全国青少年信息素养大赛复赛真题(算法应用主题赛C++初中组:带解析)(7月4日试卷一)【文末附答案和解析】

王老师青少年编程 1738

字符串拼接之String、StringBuilder、StringBuffer

字符串拼接之String、StringBuilder、StringBuffer 在写Java代码的过程中,我们经常会用到字符串的拼接,但是你知道他们的区别?废话不多说,直接上测试代码。 一. 效率比较 1. String拼接代码 public static String testString(int appendTimes) { String str =...

既无风雨也无晴 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java中的String

我们先对String来简单介绍一下: 1.字符串,使用“”引起来表示 2.声明为final,不可被继承 3.实现了Serializable接口,字符串可以被序列化 4.实现了Comparanle接口,可以用来比较字符串的大小 5.一种不可变的字符序列-->不可变性 6.String是引用类型 不是基本数据类型 7.可通过字面量的方式或者String构造器的方式给字符串进行赋值 一、String两种实例化 /** * String 实例化 * 方式一:通过字面量定义的方式 *

weixin_53870975的博客 698

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

别再乱用String拼接了!Java字符串拼接最佳实践与避坑指南

本文深入剖析了Java中String、StringBuilder和StringBuffer的性能差异与适用场景。针对常见的字符串拼接性能陷阱,特别是循环中使用“+”操作符导致大量临时对象的问题,提供了最佳实践与避坑指南。文章通过性能对比和实战代码示例,指导开发者根据单线程、多线程、循环、SQL构建等不同场景,选择最高效的字符串拼接方式,并介绍了StringJoiner、文本块等现代Java特性。

weixin_28363123的博客 108

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Java源码剖析—2 String源码分析

Java String 源码分析

huang_zhiwei的博客 469

c++把int转换成string_面试官:你工作三年了,还是不懂String!

前语:不要为了读文章而读文章,一定要带着问题来读文章,勤思考。来源:http://1t.click/aktS# switch对String的支持在介绍string的字符串操作之前,先说说switch对String的支持,大家都知道在Jdk1.7之前switch只能局限于int 、short 、byte 、char四类做判断条件。而在JVM内部实际大部分字节码指令只有int类型的版本,在使...

weixin_39878401的博客 105

java基础篇:String

具体原因为:人们使用拉丁字符(Latin-1)居多,char数组中每一个char会占用俩个字节而拉丁字符只需一个字节即可存储,剩下的一个字节就浪费掉了,造成了内存的浪费,gc的也更加频繁,因此在jdk1.9将String底层改为了 byte[ ]。我们都知道char类型是可以存储一个中文汉字的,因为java中使用的编码是unicode,而char类型占俩个字节(16bit),所以存储一个中文汉字是没有问题的。那么问题来了,在jdk1.9中不是将String底层改为了 byte[ ] 吗。

x² 1420

Java String 对 null 对象的容错处理

Java String 对 null 对象的容错处理 最近看到这样一段话: 原生类型会被自动初始化为 0,但是对象引用会被初始化为 null,如果你尝试调用该对象的方法,就会抛出空指针异常。通常,你可以打印一个 null 对象而不会抛出异常。 第一句相信大家都会容易理解,这是类型初始化的基础知识,但是第二句就让我很疑惑:为什么打印一个 null 对象不会抛出异常?带着这个疑问,我开始...

精彩人生从此刻开始 1万+

Java String深度探幽

Java String深度探幽01. 概述02. 内存分析2.1 常量赋值2.2 new对象2.3 字符串常量拼接操作(+)2.4 非常量字符串拼接(+)04. intern方法05. 总结 01. 概述 类定义public final class String implements java.io.Serializable, Comparable<String>, Cha...

we.think 437
上一篇: java_多线程死锁
下一篇: 带checkBox的ListView
izard999
博客等级 码龄18年 375粉丝 98原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值