剖析java中的String之__拼接

分类: java 2011-08-24 17:46 31人阅读 评论(0) 收藏 举报

出处, http://blog.csdn.net/izard999/article/details/6708433

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

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

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

view plain
  1. String s = null;
  2. s += "abc";
  3. 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不同,则并行执行(相互之间不互斥)。原始代码如下:

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

此题解题的思路有很多种,不可或缺的步骤就是在doSome方法内部用synchronized(o)把那个写了注释的代码块同步, 有些人肯定会说:

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

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

this.key = key + key2;

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

view plain
  1. String a = "a" + "b";
  2. String b = "a" + "b";
  3. System.out.println(a == b);

这段代码输出true没有问题

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

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

view plain
  1. String a = "a";
  2. String b = "b";
  3. String s1 = a + b;
  4. String s2 = a + b;
  5. System.out.println(s1 == s2);

这个输出就是false!

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

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

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

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

剖析java中的String之__拼接相关推荐

  1. Java中,String类字符串拼接 用concat方法 和直接用“+”连接符拼接的区别

    在String类中,字符串拼接既可以使用concat方法,也可以直接用连接符进行连接,那么两者有什么相同点和不同点呢,下面小编带大家通过代码一起来看一下. concat方法的使用:public Str ...

  2. Java中三种字符串的拼接(++ , String.format , StringBuilder.append)

    在Java中 , 对字符串内容的拼接是比较常见的操作 , 通常有三种方式 . 用String类重载'+'运算符进行拼接本质上是调用StringBuilder.append . 用类似C的printf风 ...

  3. Java中的String、StringBuilder、StringBuffer

    Java中的String是个永恒的话题,直说我想说的. 1.String 是永远不会变的,传递的引用是一个Copy,无论刮风下雨,它都在自己的小窝里呆的好好的. 2.重载"+"和S ...

  4. c++中string插入一个字符_Java内存管理-探索Java中字符串String(十二)

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 一.初识String类 首先JDK API的介绍: public final class String extends O ...

  5. Java中的String,StringBuilder,StringBuffer的区别

    这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > ...

  6. Java 中的 String、StringBuilder、StringBuffer 的区别

    目录 一.是什么? 二.区别是? 1. 运行速度(执行速度) 2. 线程安全 三.小结 四.加餐 一.是什么? String 不可变字符序列 String 是字符串常量,其对象一旦创建之后该对象是不可 ...

  7. string类转数组 java_将java中的 string 类型转成 数组案例

    这个要看你的具体需求了.如果是有分隔符的那种例如"a,b,c";就直接分割就行了. String string = "a,b,c"; String [] str ...

  8. 深入理解Java中的String(原地址https://www.cnblogs.com/xiaoxi/p/6036701.html)

    深入理解Java中的String 一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码: public final class Stringimplem ...

  9. Java中的String,StringBuilder,StringBuffer三者的区别

    最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...

最新文章

  1. leetcode[161] One Edit Distance
  2. 游戏UI设计干货:怎么让游戏界面更具科技感?
  3. 关于Visual Studio 2017安装需要注意的细节
  4. 使用aSpotCat控制您的Android应用权限
  5. 山东自考c语言程序设计停考了吗,山东自考教育类停考专业遗留问题的通知
  6. JavaScript之对象学习
  7. C++语言基础 例程 派生类的声明与构成
  8. oracle如何查询明细账,新纪元通用账证查询打印软件常用问题解答.docx
  9. 苹果4s怎么越狱教程_苹果手机:使用Rollectra工具清除iOS11.3~11.4beta3越狱教程
  10. Linux傲腾内存,傲腾内存价格流出:每GB最低35元,最高容量512GB
  11. 单应性变换(Homography)的学习与理解
  12. vs2010的Visual Assist X破解版安装
  13. 内网穿透群晖NAS:免费安装cpolar群晖套件 1/2
  14. 如何找出C#的dataGridView中某字段重复的行并将重复行标红(基于汉得MES系统)
  15. 狡猾的老鼠 -有一只狡猾的老鼠,在一个环形的田埂上挖了n个老鼠洞,这些洞也是连接为一个环状,我们要用泥土填满这些鼠洞,老鼠从第0号洞开始出现(第0号洞不填),然后依次按每间隔m个洞出现一次。我们要跟在
  16. java 文件路径读取,java中依据路径读取文件
  17. VS Code-SynthWave '84主题与字体霓虹灯(发光)效果 小白安装教程
  18. 公差带与配合 常用基孔制公差带的相互关系
  19. 无速度矢量控制+飞车启动,全速度段可追踪,s functin,纯C代码,大厂内部资料,可移植DSP28X系列。
  20. XP安装SQLSERVER企业版

热门文章

  1. 判断字符为空_算法题:字符串转换整数 (atoi)
  2. 如何判断是不是真正的物理隔离网络光端机
  3. PDH-SDH光端机指示灯具体含义介绍
  4. 计算机考博哪个学校好考,管理学博士哪个学校好考
  5. php odbc驱动,用于Windows的PHP 7.0 ODBC驱动程序
  6. mysql 5.6自动任务_mysql定时执行某任务
  7. Android Studio is on board
  8. zen of python什么意思_如何理解「The Zen of Python」?
  9. oracle 查询过去一个星期的数据_过去一星期,最懂我的居然是一个表情包
  10. oracle存储过程深入,深入了解oracle存储过程的优缺点