java的string类源码_String类——StringBuilder类的源码及内存分析(java)

相同:底层均采用字符数组value来保存字符串

区别:String类的value数组有final修饰,指向不可改,同时private未提供修改value数组的方法。StringBuilder类的value数组没有final修饰,可以改变指向,且可以扩容,扩容通过新建字符数组完成。

首先分析String的源码:

5584e6a7501fb7c38c6107c665f49281.png

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

例如:下列字符数组c为final修饰,表示c的指向不变,但修改c的内容是可行的。

ff110fc4479247240883122e838a1170.png

赋值前后的内存变化:

赋值前:

42e356550d4800906354f72837e187ec.png

赋值后:

5c0f3fdbd0a837ae7c2215bba21f7c0d.png

第一部分:构造函数

接下来看看常用的String类的构造函数:

首先空串 ”” 和 “abcd” 都是字符串对象

4839847689d8187aba492a317d746245.png

再看这两个构造函数:

5f15fa752e48c56b75e8fe2c2508198a.png

对于以下代码:

String str1 = newString();

String str2= new String(“abcd”);

在构造函数中分别对应:

this.value =“”.value;this.value = “abcd”.value;

是将 “” 的value值赋予str1的value,将“abcd” 的value所指对象赋给str2的value:

8587c9fd574d2c1d1fb0b5f38abeb37d.png

0d0a2a6fc268b908eb96407fdc3c1618.png

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

790ec2eb0c7ae3d79a871469d9acd64c.png

该函数使用数组复制函数,将参数数组c复制给str3的字符数组value

再看看数组复制函数Arrays.copyOf():

6413d862856f08a95e4d9cb74ffa8bd3.png

其中参数original是要被复制的字符数组,newLength是要复制的长度,也是新数组的长度。函数返回复制完的新数组。

char[] c ={‘a’, ‘b’, ‘c’, ‘d’};

String str3= new String(c);

的内存分析如下:

8e5a10bf270c59c48d2c2dbb02ee930a.png

第二部分 常用函数

length()函数,返回的是字符数组value的长度

ec04a8f66d49ace9450af86deedd631c.png

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

4d1dfc0ee19ae7f1131665fc8c84a7d8.png

3.重写的 equals函数

d50f5799de7c7f218838a0f8d48748f5.png

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

00b86df395406b4de7f3507ef845e9f8.png

函数为真的两种情况:

情况一:指向同一对象

4bb2a1c888651d883b79a116072c9da9.png

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

1b22993065a9af39dee8ab57da522f07.png

4.compareTo() 函数

bb74befb8fa53e97123d65c675029538.png

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

5.substring 函数

substring(int)

fc25c820177e6394b282589bc0432b45.png

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

substring(int, int):

a308fba8366b1e9ee88da78c4a24979f.png

35ecd314a65225b067196753e81a8351.png

如果要获取的子串是从0到最后,则返回原本的String对象,否则返回一个新的String对象。

6.字符替换 replace(char, char);

5bb4dcdbcf9ce0cbf7947b3231f5afbe.png

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

7.toString函数

0e3f29ab07d924cd0889797d80294d82.png

因为已经是String对象,所以返回自身。

接来下看StringBuilder类的源码:

StringBuilder类也是由final修饰,即也不能被继承。同时该类继承了抽象父类AbstractStringBuilder.

fbdce626ecb478b44ad8d36e21749c56.png

第一部分   构造函数

StringBuilder strb = new StringBuilder();

可以看到构造函数对父类构造函数传的参数为16,分析父类对应的构造函数:

888d7c196e51d02eab513f0e118c6670.png

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

7240c36749bf48efccc9b642dbdccf48.png

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

另一个构造函数:

StringBuilder strb = new StringBuilder(20);

7a7f69d1060737ad67a8a926958b7ac7.png

即通过父类构造函数,创建一个新的字符数组。该数组长度为参数值。

传入字符串的构造函数:

StringBuilder strb = new StringBuilder(“abcd”);

7a2f067eff99d0239838a7ad17d580c6.png

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

a6fc1bfe770412fb6cf03f6eabfdfd03.png

先调用父类的append方法:

a28ac422e55f47d2e932d1ae9ef234b5.png

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

d199e16be192e672b67f1e7d8943dfbc.png

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

enpandCapacity函数源码:

50f176a888bc054337f9bd4764cd371e.png

扩容的新容量为当前value的容量2倍加2,如果扩容后的容量还是比需要的最小容量小,则直接扩容为需要的最小容量,再将当前value内容复制给一个新的长度为newCapacity的字符数组,再将value指向这个扩容后的新数组。即扩容是通过开辟新数组完成的,返回的也是新创建的新数组。

接着,append函数执行完ensureCapacityInternal函数后,this对象的value数组已经指向一个扩容后的新数组,并且之前的value数组里的值也复制到新的value数组中,接下来执行getChars函数:

getChars函数源码:

9693c4ac7ac7fb5e1cf30b3a0f5c178e.png

即该函数是将调用的string对象的value数组从srcBegin到srcEnd复制给目标数组dst,从dst数组的第dstBegin位置开始。

append函数中执行完str.getChars函数后就将参数str的内容追加到StringBuilder对象的value数组后面,再更新count值,返回调用对象。

内存可以描述为:

70a4ab84aaa4dbd42012a3101986a4a2.png

第二部分  常用函数

删除函数

deleteCharAt(int)

1ba1860365b319942ed068db9f2bb7a8.png

看父类的对应函数

aac72bd090dadd1878aebce83209ad93.png

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

2.插入函数insert(int, char)

7bcabbf92e07bbc32cc953b5f1a51398.png

父类对应函数:

3138a15274cb9746192dbc7218a46597.png

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

3.toString函数

3aeb780321182c54ead69512935009bc.png

返回一个新创建的String对象,内容为value保存的字符。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值