意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

java基础实战1之String、StringBuilder、StringBuffer

来源:恒创科技 编辑:恒创科技编辑部
2024-01-26 23:40:59
java基础实战1之String、StringBuilder、StringBuffer

大家好,第一次写文章,最近想复习一下整理下自己的技术栈,发现写文章的方式不错,既能提高自己的严谨性,也能通过分享让大家看到我的想法,也能纠正我的一些认知错误。这不是基础哈,只是整理我在开发中使用的一些感想注意事项,和自己的一些理解。当然也希望能帮到大家,写的不好,有问题希望大家多多和我交流。

String 是大家常用的类,还有基础面试的时候经常会被问到String和StringBuilder、StringBuffer有什么区别呢。记得我刚才第一次面试的时候,就遇到了这个问题,也有点蒙圈,可能是第一次经历有些紧张,其实之前在培训或者书中的确讲过,也看过,但是不太理解,所以没有记住。面试后赶紧查阅资料,赶紧背,避免在以后的面试中被问到(所以大家无论找不找工作,其实都可以去试试主要是看看目前市场用的什么技术,也可以检测一下自己目前的能力,给自己的知识体系扫一下盲点)。 言归正传,以前刷题的时候,看了很多分享文章,但感觉不是很清晰,线程安全问题比较好理解因为加了synchronized关键字了,但是其他方面,比如:String怎么就不可变了?是因为没提供API 吗?如果提供了API,不能修改原内存上的数据吗?StringBuiler为什么就是可变的? 下面跟大家分享下我的理解。

1、String的不可变。

首先可以看到String内部是用基础类型char[]来存放的。 图片.png

再看下面进入Arrays.copyOf方法中 图片.png

下层new了一块空间,长度是字符串的长度。然后执行了System.arraycopy方法。

图片.png

我认为它的不可变主要是体现在,第一、当两个字符串拼接的时候,例如:“a”+“b”,它是新建了一块空间把a和b方进入,而不是直接在之前的char[]数组中追加。

图片.png 追加不了的原因是,之前定义的“a”和“b”的时候没有申请那么大的空间,说句大白话就是当时定义的时候都是可丁可卯的,“a”长度就是1 ,’b’的长度也是1,再追加一个字符没有那么大的空间,第二 修改的话String类也没有提供对应的API来操作(我觉着其实String可以提供个更新setChar(字符,index)接口,也不影响嘛)。

注意容易出错的地方:图中final修饰的char[] ,只是修饰这个变量引用的地址不变,不是说值不可以改变。可以看下面图cs1不能指向cs2,因为cs1被final了。

图片.png 我们修改cs1数组里的内容是可以的。 图片.png

2、StringBuilder的可变

相对String的不可变,其实StringBuilder可变,只是是在申请空间的时候多申请了一些,并提供了,append,setChar(char,index) 等编辑api,我们再追加字符串时,如果不超过cap,是可以直接放到后面的。我们也可以根据业务,在自己定义大小。 图片.png 图片.png 图片.png 调用append方法 图片.png 当append追加的字符+现在的内容,长度小于之前新创建的空间时。会直接追加到末尾,。 例如: StringBuilder(cap:16) ={a,空位,空位…} ,当我们插入c时,那么直接在索引1(从0开始)的位置插入b,变为{a,b,空位…}。 图片.png 当append追加的字符串+现在的内容,长度大于之前新创建的空间时,例如:StringBuilder(cap:4) ={a,b,空位, 空位} 当我们插入c、d时,这时它也会调用arrays.copy,然后并且进行new char新建一块空间,然后进行System.arraycopy和String一样。 图片.png 图片.png

3、StringBuffer和StringBuilder的区别:

这个就不多说了,StringBuffer和StringBuilder的区别,可以看到StringBuffer有synchronized的锁,多线程的时候他是安全的。当多线程访问StringBuffer定义的static变量时,不会有可见性、并发的问题。

总结:

1、一般情况下,字符串我们不改或者改的次数很少不影响性能的时候,可以使用String。例如:一般java用作web开发时,String定义的变量只是用来接收DB中字段的数据,不会去修改。 图片.png 或者DB中存放的是1或0,java收到后要转换成中文正常或不正常,那么我们可以使用String。而如果使用StringBuilder,因为它初始化时新建的空间会比实际需要的空间大,所以会有影响。 图片.png 如果使用Stringbuilder的话:可以看到它默认开了16个空间来存放 2个值。(当然大家也可以设置StringBuilder的默认cap为2,不影响的话当然也没问题,要注意StringBuilder由于要支持setchar()等功能,所以要定义len属性、cap属性这些也是耗费空间的) 图片.png

2、字符串经常变更的话尽量使用StringBuilder,它满足一般的场景,每次扩容都是之前容量的2倍+2(具体数值大家可以写测试代码进行观察),它提供了setChar方法,可以进行某位置的字符更新,也能使用append,进行字符串的追加,但是要注意追加时入参的字符串长度。否则StringBuilder可能会和String一样。或者cap过大内存溢出。我们最好可以根据业务,去预先设置它的cap参数,也要注意线程安全问题。线程安全的话可以用StringBuffer因为加了synchronized锁。

测试代码:观察cap变化:每次扩容都会扩容之前容量的2倍+2。 图片.png 3、如果项目有性能要求的话,那么我们可以根据StringBuilder和String的特点,来自己进行实现。定义char[] 数组,根据业务需求来定义char[]数组的cap总容量、pos偏移位置和limit实际数据长度。来自己实现String。(有点像Byteuffer中的cap、pos、limit、mark哈哈)

好了这篇分享完了,小弟第一次分享,有不对的地方,欢迎大家多多和我交流、批评和指正。

上一篇: 在 JavaScript 中,什么时候使用 Map 或胜过 Object 下一篇: 手机怎么远程登录云服务器?