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类型字节不够存储,内存溢出


相关文章
|
17天前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
53 7
|
28天前
|
数据采集 人工智能 Java
Java产科专科电子病历系统源码
产科专科电子病历系统,全结构化设计,实现产科专科电子病历与院内HIS、LIS、PACS信息系统、区域妇幼信息平台的三级互联互通,系统由门诊系统、住院系统、数据统计模块三部分组成,它管理了孕妇从怀孕开始到生产结束42天一系列医院保健服务信息。
30 4
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
73 2
|
9天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
60 13
|
23天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
51 12
|
17天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
26天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
56 5
|
1月前
|
安全
String、StringBuffer、StringBuilder的区别
String 由 char[] 数组构成,使用了 final 修饰,对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。 StringBuffer可变并且线程安全;有一定缓冲区容量,字符串大小没超过容量,不会重新分配新的容量,适合多线程操作字符串; StringBuiler可变并且线程不安全。速度比StringBuffer更快,适合单线程操作字符串。 操作少量字符数据用 String;单线程操作大量数据用 StringBuilder;多线程操作大量数据用 StringBuffer
|
1月前
|
索引 Python
String(字符串)
String(字符串)。
30 3
|
19天前
|
人工智能 移动开发 安全
家政上门系统用户端、阿姨端源码,java家政管理平台源码
家政上门系统基于互联网技术,整合大数据分析、AI算法和现代通信技术,提供便捷高效的家政服务。涵盖保洁、月嫂、烹饪等多元化服务,支持多终端访问,具备智能匹配、在线支付、订单管理等功能,确保服务透明、安全,适用于家庭生活的各种需求场景,推动家政市场规范化发展。