Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究

简介: Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究

String temp = “a”;

这种方式,会先去找字符串常量池里是否有保存了同样值的字符串对象,如果有,那么直接将该对象的地址赋值给temp,如果没有,那么就在字符串常量池里申请地址然后存放,temp变量保存的是常量池里的地址

//看起来像是两个对象,实则是同一个对象
String one = “a”;
String two = “b”;
sout(one == two);

第二种就是使用构造方法创建

构造方法可以根据字符串或者字符数组去建立

不过,这里与第一种不同的是,创建的字符串对象是保存在堆中的,而不是字符串常量池里面

String three = new String(“a”);

如果使用字符串作为构造参数去构造的话,仍然要用到字符串常量池(因为要在字符串常量池新创建或者里面就有,才可以使用),如果使用到的字符串参数不用,后面会被gc收集器回收。

这样设计的优点是,可以带来共享的效率

比较

字符串比较最好不要使用双等于,而是使用equal方法

双等于比较的只是引用地址,而equal方法是先比较引用地址,然后再比较里面的值

public boolean equals(Object anObject) {
//先判断应用地址,如果相等,肯定是相同对象
if (this == anObject) {
return true;
}
//如果应用地址不正确,再判断是否是String类型
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
//遍历底层字符串底层的字符数组进行比较
//先判断底层字符数组长度是否相等,不相等也不用比了,肯定不对
if (n == anotherString.value.length){
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//进行遍历比较
while (n-- != 0) {
//只要有一个比不上,就确认不相同
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

底层

从上面的源码可以看到,底层是一个字符数组,所以,它可以存储多字节的字符。

前面提到过,字符里面存储的是代码单元,所以底层字符串数组存的就是多个代码单元,这样就可以去表示各种字符串了。

这里要提及String.length方法,返回的是字符数组的长度,也就是代码单元的长度,所以不一定是字的个数

构建字符串


常用构建字符串的构造器有StringBuffer与StringBuilder

AbstractStringBuilder

我们可以看到,无论是StringBuffer或者是StringBuilder都是继承了这个类,所我们先研究这个类

里面共有4个属性

  • value:存储字符串的(字符串底层是字符数组,默认容量为16)
  • count:记录字符数组的长度,这样做的好处就是让返回字符数组长度的时间复杂度为1,而不用去遍历数组
  • MAX_ARRAY_SIZE:字符数组允许的最大长度,为( 2 31 − 8 2^{31}-8 231−8),从注释上就可以看到,这个变量并不是必要的,只不过是避免大数组会导致内存溢出(超出虚拟机的限制)。

下面就来看看append的源码

public AbstractStringBuilder append(String str) {
//判断是否为空
if (str == null)
//没有的话就调用这个方法,这个方法其实是返回一个NULL,然后value里面就存储了Null
return appendNull();
//记录长度
int len = str.length();
//也是判断底层数组长度是否足够,不够就要进行扩容
ensureCapacityInternal(count + len);
//调用字符串的getChars方法进行拼接
str.getChars(0, len, value, count);
count += len;
return this;
}
appendNull的实现
private AbstractStringBuilder appendNull() {
//就很简单使用一个字符数组,存储null,然后返回
int c = count;
//判断底层数组的长度是否足够,不够需要进行扩容
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = ‘n’;
value[c++] = ‘u’;
value[c++] = ‘l’;
value[c++] = ‘l’;
//记录此时底层字符数组长度
//至于这里为什么只用count = c
//看看value[]里面的是什么
//再看看c是什么吧
count = c;
return this;
}
ensureCapacityInternal的实现
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
//minimumCapacity是最小需要的底层字符数组长度
if (minimumCapacity - value.length > 0) {
//如果不够,进行复制
//不够的话,要按照规则进行扩容
//Arrays.copyof其实就是新建一个数组然后存放而已
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
newCapacity的实现(扩容的规则)
private int newCapacity(int minCapacity) {
// overflow-conscious code
//新的规则为,底层数组长度话为二进制然后左移一位,相当于扩展2倍
//然后再加2,所以新道德数组长度为原来的2倍加2
int newCapacity = (value.length << 1) + 2;
//再判断新的长度是否大于旧的长度
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//如果新的长度不小于0(这里可能是因为超过了int类型的4个字节),
//又不大于最大底层字符数组长度(这个变量防止内存溢出)
//就返回新的长度
//如果大于最大底层数组长度,就调用hugeCapacity
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)newCapacity;
}
hugeCapacity的实现:处理超大底层数组长度
private int hugeCapacity(int minCapacity) {
//如果是newCapacity <= 0,代表int类型字节不够存储,内存溢出


目录
打赏
0
1
1
1
80
分享
相关文章
鸿蒙开发:ArkTs字符串string
字符串类型是开发中非常重要的一个数据类型,除了上述的方法概述之外,还有String对象,正则等其他的用处,我们放到以后得篇章中讲述。
84 19
[Java计算机毕设]基于ssm的OA办公管理系统的设计与实现,附源码+数据库+论文+开题,包安装调试
OA办公管理系统是一款基于Java和SSM框架开发的B/S架构应用,适用于Windows系统。项目包含管理员、项目管理人员和普通用户三种角色,分别负责系统管理、请假审批、图书借阅等日常办公事务。系统使用Vue、HTML、JavaScript、CSS和LayUI构建前端,后端采用SSM框架,数据库为MySQL,共24张表。提供完整演示视频和详细文档截图,支持远程安装调试,确保顺利运行。
78 17
|
1月前
|
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
当我们创建一个`ThreadPoolExecutor`的时候,你是否会好奇🤔,它到底发生了什么?比如:我传的拒绝策略、线程工厂是啥时候被使用的? 核心线程数是个啥?最大线程数和它又有什么关系?线程池,它是怎么调度,我们传入的线程?...不要着急,小手手点上关注、点赞、收藏。主播马上从源码的角度带你们探索神秘线程池的世界...
121 0
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
智慧产科一体化管理平台源码,基于Java,Vue,ElementUI技术开发,二开快捷
智慧产科一体化管理平台覆盖从备孕到产后42天的全流程管理,构建科室协同、医患沟通及智能设备互联平台。通过移动端扫码建卡、自助报道、智能采集数据等手段优化就诊流程,提升孕妇就诊体验,并实现高危孕产妇五色管理和孕妇学校三位一体化管理,全面提升妇幼健康宣教质量。
64 12
干货含源码!如何用Java后端操作Docker(命令行篇)
只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java智慧工地(源码):数字化管理提升施工安全与质量
随着科技的发展,智慧工地已成为建筑行业转型升级的重要手段。依托智能感知设备和云物互联技术,智慧工地为工程管理带来了革命性的变革,实现了项目管理的简单化、远程化和智能化。
59 5
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
课时16:String字符串
课时16介绍了Java中的String字符串。在Java中,字符串使用`String`类表示,并用双引号定义。例如:`String str = &quot;Hello world!&quot;;`。字符串支持使用“+”进行连接操作,如`str += &quot;world&quot;;`。需要注意的是,当“+”用于字符串与其他数据类型时,其他类型会先转换为字符串再进行连接。此外,字符串中可以使用转义字符(如`\t`、`\n`)进行特殊字符的处理。掌握这些基本概念对Java编程至关重要。
|
29天前
|
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
55 11
|
1月前
|
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等