1.String

  1. public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
  2.  
  3. //存储字符,final修饰
  4. private final char value[];
  5.  
  6. //缓存hash code,默认0
  7. private int hash;
  8.  
  9. //序列号
  10. private static final long serialVersionUID = -6849794470754667710L;
  11.  
  12. //声明可序列化字段
  13. private static final ObjectStreamField[] serialPersistentFields =
  14. new ObjectStreamField[0];
  15. }

1.1 基本属性

  • char value[],用来存储字符串对象的字符数组
  • int hash,用来缓存字符串的hash code,默认值为0
  • long serialVersionUID,用来序列化的序列版本号
  • ObjectStreamField[],可序列化类的字段说明

1.2 常用构造器

  1. public String() {
  2. this.value = "".value;
  3. }

初始化新创建的对象,表示空字符串""。请注意,此构造函数是不需要使用的,因为字符串是不可变的.
String str = new String(); 本质上是创建了一个空的字符数组,str的长度为0

  1. public String(String original) {
  2. this.value = original.value;
  3. this.hash = original.hash;
  4. }

初始化新创建的对象,表示和参数一样的字符串,换句话说是创建了和参数一样的对象副本,除非需要显示的声明副本,否则该构造函数是不需要的,因为字符串是不可变的

  1. public String(StringBuffer buffer) {
  2. synchronized(buffer) {
  3. this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
  4. }
  5. }

把StringBuffer的内容复制到String对象中,随后修改StringBuffer对象的值,并不会影响String对象

  1. public String(StringBuilder builder) {
  2. this.value = Arrays.copyOf(builder.getValue(), builder.length());
  3. }

把StringBuilder的内容复制到String对象中,随后修改StringBuilder的值,并不会影响String对象;
此构造函数是为了把StringBuilder转移到String对象,但是推荐使用StringBuilder的toString()方法,因为运行更快

1.3 常用方法

  1. //返回字符串的长度
  2. public int length() {
  3. return value.length;
  4. }
  5.  
  6. //比较两个String值是否相等
  7. public boolean equals(Object anObject) {
  8. if (this == anObject) {
  9. return true;
  10. }
  11. if (anObject instanceof String) {
  12. String anotherString = (String)anObject;
  13. int n = value.length;
  14. if (n == anotherString.value.length) {
  15. char v1[] = value;
  16. char v2[] = anotherString.value;
  17. int i = 0;
  18. while (n-- != 0) {
  19. if (v1[i] != v2[i])
  20. return false;
  21. i++;
  22. }
  23. return true;
  24. }
  25. }
  26. return false;
  27. }
  28.  
  29. //生成hash code
  30. public int hashCode() {
  31. int h = hash;
  32. if (h == 0 && value.length > 0) {
  33. char val[] = value;
  34.  
  35. for (int i = 0; i < value.length; i++) {
  36. h = 31 * h + val[i];
  37. }
  38. hash = h;
  39. }
  40. return h;
  41. }
equals方法的判断流程:
  • 首先判断两个对象是否相同,若相同返回true;若不同,下一步
  • 判断参数是否为String对象,若不是,返回false;若是,下一步
  • 判断两个String的长度是否相等,若不是,返回false;若是,下一步
  • 按字符数组索引依次比较字符,如果有任一不相同,返回false,否则返回true

这里可以看到equals方法的实现也是调用了==来比较对象是否相同,因此在讨论equals和==区别的时候 要全面分析.

1.2 为什么说String是不可变对象?

存储字符的数组value[]是final修饰的,值不可更改.

2. AbstractStringBuilder

可变的字符序列,StringBuilder和StringBuffer都继承了该类,要了解StringBuilder和StringBuffer首先先了解AbstractStringBuilder.

2.1 基本属性

  1. abstract class AbstractStringBuilder implements Appendable, CharSequence {
  2. /**
  3. * The value is used for character storage.
  4. */
  5. char[] value;
  6.  
  7. /**
  8. * The count is the number of characters used.
  9. */
  10. int count;
  11. }

char[] value: 存储字符的数组
int count: 存储的字符的数量

2.2 构造器

  1. /**
  2. * 无参构造器,用于子类序列化
  3. */
  4. AbstractStringBuilder() {
  5. }
  6.  
  7. /**
  8. * 指定字符数组容量
  9. */
  10. AbstractStringBuilder(int capacity) {
  11. value = new char[capacity];
  12. }

2.3 常用方法

  1. /**
  2. * 返回字符的数量
  3. */
  4. @Override
  5. public int length() {
  6. return count;
  7. }
  8.  
  9. /**
  10. * 返回当前可存储字符的最大数量,即容量
  11. */
  12. public int capacity() {
  13. return value.length;
  14. }
  15.  
  16. /**
  17. * 保证当前容量大于等于指定的最小数量minimumCapacity,会调用扩容方法
  18. */
  19. public void ensureCapacity(int minimumCapacity) {
  20. if (minimumCapacity > 0)
  21. ensureCapacityInternal(minimumCapacity);
  22. }
  23.  
  24. /**
  25. * 扩容,只有minimumCapacity大于当前容量,才会copy数组扩容
  26. */
  27. private void ensureCapacityInternal(int minimumCapacity) {
  28. // overflow-conscious code
  29. if (minimumCapacity - value.length > 0) {
  30. value = Arrays.copyOf(value,
  31. newCapacity(minimumCapacity));
  32. }
  33. }
  34. /**
  35. * 当前对象拼接字符串str
  36. * 如果参数为null,那么最终字符串为"null",如果参数类型为boolean,那么返回的是"true"或"false"
  37. * 例1: "abc".append(null) = "abcnull"
  38. * 例2: "abc".append(false) = "abcfalse"
  39. */
  40. public AbstractStringBuilder append(String str) {
  41. if (str == null)
  42. return appendNull();
  43. int len = str.length();
  44. ensureCapacityInternal(count + len);
  45. str.getChars(0, len, value, count);
  46. count += len;
  47. return this;
  48. }

3. StringBuilder

可变的字符序列,非线程安全,StringBuilder和StringBuffer的实现方法很相似,区别在于是否线程安全,在单线程的情况下可使用StringBuilder,因为它比StringBuffer运行更快.StringBuilder继承了AbstractStringBuilder类.

3.1 基本属性

继承父类

3.2 构造器

  1. /**
  2. * 默认容量16
  3. */
  4. public StringBuilder() {
  5. super(16);
  6. }
  7.  
  8. /**
  9. * 指定初始容量
  10. */
  11. public StringBuilder(int capacity) {
  12. super(capacity);
  13. }
  14.  
  15. /**
  16. * 把String字符串初始化到对象中,容量变为str的长度+16
  17. */
  18. public StringBuilder(String str) {
  19. super(str.length() + 16);
  20. append(str);
  21. }
  22.  
  23. /**
  24. * 把字符初始化到对象中,容量变为字符的长度+16
  25. */
  26. public StringBuilder(CharSequence seq) {
  27. this(seq.length() + 16);
  28. append(seq);
  29. }

3.3 常用方法

同父类

4. StringBuffer

可变的字符序列,线程安全,StringBuffer继承了AbstractStringBuilder类.

4.1 基本属性

继承父类,同时还有属性toStringCache
这里涉及到一个关键字transient,其作用是让某些被修饰的成员属性变量不被序列化,为什么不需要序列化呢?主要是因为这个变量可能为null,也可能非空,不能准确的代表StringBuffer的属性.所以没有必要序列化,也节省了空间.

  1. public final class StringBuffer extends AbstractStringBuilder
  2. implements java.io.Serializable, CharSequence{
  3.  
  4. /**
  5. * 最后一次调用toString返回值的缓存
  6. * 当StringBuffer被修改时该缓存被清除
  7. */
  8. private transient char[] toStringCache;
  9.  
  10. /** 序列号 */
  11. static final long serialVersionUID = 3388685877147921107L;
  12. }

4.2 构造器

同StringBuilder

4.3 常用方法

与StringBuilder方法基本相同,区别在于在StringBuilder的方法上加了synchronized锁. 不同的地方还包括每个修改对象的方法,比如append方法都会清除toStringCache缓存.

  1. @Override
  2. public synchronized StringBuffer append(String str) {
  3. toStringCache = null;
  4. super.append(str);
  5. return this;
  6. }
  7. @Override
  8. public synchronized String toString() {
  9. if (toStringCache == null) {
  10. toStringCache = Arrays.copyOfRange(value, 0, count);
  11. }
  12. return new String(toStringCache, true);
  13. }
  1. 在调用toString方法的时候,会先判断缓存toStringCache是否存在,如果不存在,那么把当前对象赋值给toStringCache,然后得到toStringCache的字符串;如果toStringCache已经存在,那么直接读取缓存的字符串.
  2. toStringCache是否存在依赖于StringBuffer对象是否被修改,如果被修改了,那么缓存被清空.

5.总结

  1. String,StringBuilder,StringBuffer这三个类都可以创建和操作字符串;
  2. 不同点在于String是不可变的,不存在线程安全问题;StringBuilder和StringBuffer字符串是可变的,StringBuilder线程不安全,StringBuffer线程安全;
  3. 对于简单的字符串赋值和拼接操作,可使用String
  4. 对于字符串频繁修改和拼接操作,不建议使用String,因为每次操作都需要创建一个String对象,单线程推荐使用StringBuilder,多线程推荐使用StringBuffer.

JDK源码分析系列---String,StringBuilder,StringBuffer的更多相关文章

  1. JDK源码学习系列03----StringBuffer+StringBuilder

                         JDK源码学习系列03----StringBuffer+StringBuilder 由于前面学习了StringBuffer和StringBuilder的父类A ...

  2. HashMap源码分析(一):JDK源码分析系列

    正文开始 注:JDK版本为1.8 HashMap1.8和1.8之前的源码差别很大 目录 简介 数据结构 类结构 属性 构造方法 增加 删除 修改 总结 1.HashMap简介 HashMap基于哈希表 ...

  3. 【JDK源码分析】String的存储区与不可变性

    // ... literals are interned by the compiler // and thus refer to the same object String s1 = " ...

  4. 【JDK源码分析】String的存储区与不可变性(转)

    // ... literals are interned by the compiler // and thus refer to the same object String s1 = " ...

  5. 【JDK源码分析】String的存储区与不可变 专题

    <Think in Java>中说:“关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系”. "=="判断的是两个对象的内存地址是否一样,适用于 ...

  6. JDK源码分析系列02---ArrayList和LinkList

    ArrayList和LinkList的源码分析 概要 ArrayList和LinkList是常用的存储结构,不看源码先分析字面意思,Array意思是数组,可知其底层是用数组实现的,Link意思是链接, ...

  7. JDK源码分析(8) StringBuffer & StringBuilder

    简介 StringBuffer与StringBuilder是两个常用的操作字符串的类.大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的.前者是JDK1.5加 ...

  8. LinkedList源码分析:JDK源码分析系列

    如果本文中有不正确的地方请指出由于没有留言可以在公众号添加我的好友共同讨论. 1.介绍 LinkedList 是线程不安全的,允许元素为null的双向链表. 2.继承结构 我们来看一下LinkedLi ...

  9. JDK源码分析(一)—— String

    dir 参考文档 JDK源码分析(1)之 String 相关

随机推荐

  1. 关于 Facebook 的 React 专利许可证

    本文转载自:酷 壳 – CoolShell 作者:陈皓 随着 Apache.百度.Wordpress 都在和 Facebook 的 React.js 以及其专利许可证划清界限,似乎大家又在讨论 Fac ...

  2. 联想K860 ROM 从官方Vibe 精简 提高性能

    ROM介绍 从官方:根据官方Vibe 1403 6从编译版本 除去不想要的软件的一部分 自己Root权限最新版本Superuser 园林绿化导航虚拟按键 优化系统.更顺畅 提升游戏性能 优化自己主动调 ...

  3. abp框架(aspnetboilerplate)设置前端报错显示

    abp在后端抛出异常 throw new UserFriendlyException($"抛出一个错误"); 在发布之前,需要设置是否把报错发送给前端 如果将此设置为true,则会 ...

  4. Kubernetes使用集群联邦实现多集群管理

    Kubernetes在1.3版本之后,增加了“集群联邦”Federation的功能.这个功能使企业能够快速有效的.低成本的跨区跨域.甚至在不同的云平台上运行集群.这个功能可以按照地理位置创建一个复制机 ...

  5. 2-16 mysql主从复制

    1. 部署MYSQL主从同步 <M-S> 环境:mysql版本一致,均为5.7.18 master xuegod4  ip  192.168.10.34   数据库密码 yourpassw ...

  6. 基于IdentityServer4的单点登录——项目基本结构与流程

    组成 IdentityServer,Api和Client(客户端,asp .net core)本文以官方demo:https://github.com/IdentityServer/IdentityS ...

  7. WPF中的图像处理简介

    原文:WPF中的图像处理简介 和Winform中的GDI+相比,WPF提供了一组新的API用于显示和编辑图像.新API特点如下: 适用于新的或专用图像格式的扩展性模型. 对包括位图 (BMP).联合图 ...

  8. 【Python】设备重启测试

    ①添加读取键盘输入功能,方便测试者选择压测次数! Python提供了 input() 内置函数从标准输入读入一行文本,默认的标准输入是键盘. input 可以接收一个Python表达式作为输入,并将运 ...

  9. 基于开源软件构建高性能集群NAS系统,包括负载均衡(刘爱贵)

    大数据时代的到来已经不可阻挡,面对数据的爆炸式增长,尤其是半结构化数据和非结构化数据,NoSQL存储系统和分布式文件系统成为了技术浪潮,得到了长足的发展.非结构化数据目前呈现更加快速的增长趋势,IDC ...

  10. SqlServer 复制中将大事务分成小事务分发

    原文:SqlServer 复制中将大事务分成小事务分发 在sql server 复制中,当在发布数据库执行1个大事务时,如一次性操作 十万或百万以上的数据.当操作数据在发布数据库执行完成后 ,日志读取 ...