String类——StringBuilder类的源码及内存分析(java)
相同:底层均采用字符数组value来保存字符串
区别:String类的value数组有final 修饰,指向不可改,同时private 未提供修改value数组的方法。StringBuilder类的value数组没有final修饰,可以改变指向,且可以扩容,扩容通过新建字符数组完成。
首先分析String的源码:

可以看到String类有final修饰,所以String类不能被继承。这保证对String对象方法的调用确实运行的是String类的方法,而不是经其子类重写后的方法。往下看,是value数组,该字符数组被用于存储String的字符串,即”abcd”在String里存储为value[]:’a’, ’b’, ‘c’, ‘d’ 的字符数组,有final修饰,表示value指向的数组不变,但是数组里的值可变,但是有private修饰,且String类并没有提供修改value数组内容的方法,所以String对象的值一旦赋值就不可变。
例如:下列字符数组c为final修饰,表示c的指向不变,但修改c的内容是可行的。

赋值前后的内存变化:
赋值前:

赋值后:

第一部分:构造函数
接下来看看常用的String类的构造函数:
首先空串 ”” 和 “abcd” 都是字符串对象

再看这两个构造函数:

对于以下代码:
String str1 = new String(); String str2 = new String(“abcd”);
在构造函数中分别对应:
this.value = “”.value; this.value = “abcd”.value;
是将 “” 的value值赋予str1的value,将 “abcd” 的value所指对象赋给str2的value:


再看另一个常用的构造函数:

该函数使用数组复制函数,将参数数组c复制给str3的字符数组value
再看看数组复制函数Arrays.copyOf():

其中参数original是要被复制的字符数组,newLength是要复制的长度,也是新数组的长度。函数返回复制完的新数组。
char[] c = {‘a’, ‘b’, ‘c’, ‘d’};
String str3 = new String(c);
的内存分析如下:

第二部分 常用函数
- length()函数,返回的是字符数组value的长度

2.判空isEmpty() 函数,利用字符数组长度是否为0
3.重写的 equals函数

首先判断是否为同一个对象,若不是,再判断是否是String对象,强制转为String类型后,判断两个String对象的value数组是否长度相同,接下来对两个value字符数组的内容从0开始向后比较。即equal()为真的情况是: 两个对象相同;都是String对象且value字符数组内容相同。

函数为真的两种情况:
情况一:指向同一对象

情况二:均为String对象且value数组内容一致

4.compareTo() 函数

即在均存在字符的情况下,返回第一个不相同字符之差,前lim个字符相同(即长字符串的前lim个恰好是短字符串)则返回两个字符串长度之差。
5.substring 函数
substring(int)

该函数返回从给定参数位置起到字符串结束的新字符串。如果给定从0开始,则返回原本的String对象,否则返回一个新的String对象。
substring(int, int):


如果要获取的子串是从0到最后,则返回原本的String对象,否则返回一个新的String对象。
6.字符替换 replace(char, char);

函数先判断替换字符和被替换字符是否相同,若相同则返回原String对象,不同则先找到要替换的字符位置,接下来创建一个新的字符数组,将保存替换后的字符串,最后返回一个新的String对象。
7.toString函数

因为已经是String对象,所以返回自身。
接来下看StringBuilder类的源码:
StringBuilder类也是由final修饰,即也不能被继承。同时该类继承了抽象父类AbstractStringBuilder.

第一部分 构造函数
StringBuilder strb = new StringBuilder();
可以看到构造函数对父类构造函数传的参数为16,分析父类对应的构造函数:

父类创建了一个长度为16的字符数组,将value指向该新数组,那么value是什么呢?

即value也是字符数组,和String类不同的是,该字符数组没有final 修饰,即value的指向可以改变,同时权限为默认,即同类和同包可用,该类和StringBuilder在同一个包中。同时使用count变量记录字符个数(不同于value数组长度,value长度是容量)。
另一个构造函数:
StringBuilder strb = new StringBuilder(20);

即通过父类构造函数,创建一个新的字符数组。该数组长度为参数值。
传入字符串的构造函数:
StringBuilder strb = new StringBuilder(“abcd”);

初始StringBuilder的value数组容量设置为传入字符串长度加上16,再通过append函数将str写入,分析append函数:

先调用父类的append方法:

ensureCapacityInternal函数:参数是当前对象的value中字符长度与传入字符串长度之和,也即是value的容量最小值。

如果需要的容量最小值大于目前value容量,调用扩容函数enpandCapacity函数。
enpandCapacity函数源码:

扩容的新容量为当前value的容量2倍加2,如果扩容后的容量还是比需要的最小容量小,则直接扩容为需要的最小容量,再将当前value内容复制给一个新的长度为newCapacity的字符数组,再将value指向这个扩容后的新数组。即扩容是通过开辟新数组完成的,返回的也是新创建的新数组。
接着,append函数执行完ensureCapacityInternal函数后,this对象的value数组已经指向一个扩容后的新数组,并且之前的value数组里的值也复制到新的value数组中,接下来执行getChars函数:
getChars函数源码:

即该函数是将调用的string对象的value数组从srcBegin到srcEnd复制给目标数组dst,从dst数组的第dstBegin位置开始。
append函数中执行完str.getChars函数后就将参数str的内容追加到StringBuilder对象的value数组后面,再更新count值,返回调用对象。
内存可以描述为:

第二部分 常用函数
- 删除函数
deleteCharAt(int)

看父类的对应函数

即删除索引为index处的字符。通过调用数组复制函数来完成,将索引后面的内容依次复制到从索引开始的位置上,即通过覆盖的原理完成,更新count。
2.插入函数insert(int, char)

父类对应函数:

即将字符c 插入到索引offset位置上,首先确保value数组容量足够,然后通过数组复制,将索引位置开始全部向后移一位,再将索引位置赋值c,更新count。
3.toString函数

返回一个新创建的String对象,内容为value保存的字符。
String类——StringBuilder类的源码及内存分析(java)的更多相关文章
- 如何查看laravel门脸类包含方法的源码
以Route门脸类为例,我们定义路由时使用的就是Route门脸类,例如我们在web.php中定义的路由 use Illuminate\Support\Facades\Route; Route::get ...
- storm源码之巧用java反射反序列化clojure的defrecord获取属性值
[原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 storm源 ...
- 安卓图表引擎AChartEngine(二) - 示例源码概述和分析
首先看一下示例中类之间的关系: 1. ChartDemo这个类是整个应用程序的入口,运行之后的效果显示一个list. 2. IDemoChart接口,这个接口定义了三个方法, getName()返回值 ...
- 第九节:从源码的角度分析MVC中的一些特性及其用法
一. 前世今生 乍眼一看,该标题写的有点煽情,最近也是在不断反思,怎么能把博客写好,让人能读下去,通俗易懂,深入浅出. 接下来几个章节都是围绕框架本身提供特性展开,有MVC程序集提供的,也有其它程序集 ...
- 2018-08-27 使用JDT核心库解析JDK源码后初步分析API命名
源自术语词典API项目 · Issue #85 · program-in-chinese/overview, 打算先用早先的代码提取JDK API中的类/方法/参数名, 看看有哪些词需要翻译. 源码在 ...
- 一点一点看JDK源码(三)java.util.ArrayList 前偏
一点一点看JDK源码(三)java.util.ArrayList liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 ArrayLi ...
- 一点一点看JDK源码(五)java.util.ArrayList 后篇之sort与Comparator
一点一点看JDK源码(五)java.util.ArrayList 后篇之sort与Comparator liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JD ...
- 【原】storm源码之巧用java反射反序列化clojure的defrecord获取属性值
storm源码是clojure.java.python的混合体.在解决storm-0.8.2的nimbus单点问题的过程中需要从zookeeper上读取目前storm集群中正在运行的assignmen ...
- 源码级强力分析hadoop的RPC机制
分析对象: hadoop版本:hadoop 0.20.203.0 必备技术点: 1. 动态代理(参考 :http://weixiaolu.iteye.com/blog/1477774 )2. Java ...
随机推荐
- 【Hadoop 分布式部署 一 :分布式部署准备虚拟机 】
一.将IP配置为静态 按照 下面的操作将IP配置为静态IP 这个静态的IP地址 是你自己设置的,只要符合虚拟机的IP段就可以.最后点击 Apply 需要root密码 将网络断开 (在网络图标左键 ...
- Shell脚本(三)
摘自:菜鸟教程 http://www.runoob.com/linux/linux-shell-echo.html Shell命令 1. echo命令 字符串输出 echo "OK! \c& ...
- demoshow - webdemo展示助手
demoshow - web demo展示助手 动态图演示页面: http://www.cnblogs.com/daysme/p/6790829.html 一个用来展示前端网页demo的小“助手”,提 ...
- R语言通过loess去除某个变量对数据的影响--CNV分析
当我们想研究不同sample的某个变量A之间的差异时,往往会因为其它一些变量B对该变量的固有影响,而影响不同sample变量A的比较,这个时候需要对sample变量A进行标准化之后才能进行比较.标准化 ...
- mac终端不好用?用brew神器代替
一.概念 Brew是一款Mac OS平台下的软件包管理工具,拥有安装.卸载.更新.查看.搜索等很多实用的功能.简单的一条指令,就可以实现包管理,而不用你关心各种依赖和文件路径的情况,十分方便快捷. 官 ...
- Javascript 垃圾回收机制
转载于https://www.cnblogs.com/zhwl/p/4664604.html 一.垃圾回收的必要性 由于字符串.对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储 ...
- 力扣(LeetCode)1009. 十进制整数的反码
每个非负整数 N 都有其二进制表示.例如, 5 可以被表示为二进制 "101",11 可以用二进制 "1011" 表示,依此类推.注意,除 N = 0 外,任何 ...
- 牛客国庆集训派对Day3 A Knight
Knight 思路: bfs打表找规律 如下图 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) ...
- h5做直播的弹幕效果
最近在搞弹幕效果所以就写一个关于弹幕的吧,刚开始寻思去网上找插件的,但找的插件和我的需求都不太相符,其实做弹幕我知道的有两种方法: 1:一种是用canvas和对象来完成弹幕想过,用canvas来完成弹 ...
- 关于MySQL大量数据分页查询优化
select * form user id in(select id from user limit 1000000,10);