文档章节

String源码分析

o
 osc_g8254g7s
发布于 2019/08/20 11:40
字数 1250
阅读 18
收藏 0
jdk

前言:String类在日常开发过程中使用频率非常高,平时大家可能看过String的源码,但是真的认真了解过它么,笔者在一次笔试过程中要求写出String的equals方法,瞬间有点懵逼,凭着大致的理解,算是写出来了,可是下来一翻String的源码顿悟,原来自己写得是多么的low,所以有必要把这些基础知识点记录下来,加深印象。

注:本文jdk源码版本为jdk1.8.0_172


1.String类的基本概念

首先String是不可变对象,其体现主要在String类是被final关键字修饰,因此该对象不能被继承,不能被修改。那你可能要问了为什么我们在日常操作过程中不是可以很方便的修改String的内容吗?其实我们修改其内容是new了一个对象,原来的内容并没有改变。

String内部是通过char数组来存储的内容,从以下源码中可以发现:

注:这里的char数组也是被final修饰。

2.String的构造函数

不知道你注意没,String的构造函数非常的多:

这里挑选几个笔者认为有特点的构造函数进行分析,其它构造函数请查看相应源码。

#1.默认构造函数:

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

注:默认构造函数的实现非常简单,就是返回空字符串的数组形式。

#2.入参为char数组:

1  public String(char value[]) {
2         this.value = Arrays.copyOf(value, value.length);
3     }

分析:如果传入char数组,是通过Arrays#copyOf方法进行拷贝的。

#3.入参为String对象:

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

分析:如果入参为String对象,则直接进行相应的赋值即可(value和hash值)。

#4.入参为StringBuffer:

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

分析:这里对StringBuffer进行了加锁,然后再进行拷贝操作。为什么要对StringBuffer加锁呢?StringBuffer不是线程安全的吗?其实这里对其进行加锁正是为了保证在多线程环境下只能有一个线程去操作StringBuffer对象,这里需要注意一下。

#5.入参为StringBuilder:

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

分析:对比StringBuffer入参,如果用StringBuilder作为入参是不加锁操作的,因为StringBuilder本身线程不安全,但会提升性能,并且其源码上也做出了相应注释。

注意:以StringBuffer和StringBuilder为入参的构造函数这里要特别关注一下:StringBuffer线程安全,为了保证在String中也线程安全所以需要加锁,而StringBuilder非线程安全,因此不需要加锁操作,直接进行拷贝即可。

3.hashCode方法

 1     public int hashCode() {
 2         int h = hash;
 3         if (h == 0 && value.length > 0) {
 4             char val[] = value;
 5 
 6             for (int i = 0; i < value.length; i++) {
 7                 h = 31 * h + val[i];
 8             }
 9             hash = h;
10         }
11         return h;
12     }

分析:String的hashCode方法还是比较简单的,它是遍历char数组以31为基数做一个累加操作。注意这里是以31来作为的基数,为什么取31作为基数可参考:String hashCode 方法为什么选择数字31作为乘子

4.equals方法

 1 public boolean equals(Object anObject) {
 2         if (this == anObject) {
 3             return true;
 4         }
 5         if (anObject instanceof String) {
 6             String anotherString = (String)anObject;
 7             int n = value.length;
 8             if (n == anotherString.value.length) {
 9                 char v1[] = value;
10                 char v2[] = anotherString.value;
11                 int i = 0;
12                 while (n-- != 0) {
13                     if (v1[i] != v2[i])
14                         return false;
15                     i++;
16                 }
17                 return true;
18             }
19         }
20         return false;
21     }

分析:首先会判断是否是同一个对象,如果是,则直接返回true;其次判断传入对象是否为String对象,如果对象不匹配直接返回false,否则依次比较两个对象的char,只要发现一个不相等,则直接返回false,停止循环。这里的写法还是比较简洁的,在日常开发中可以利用起来。

5.关于不可变对象

关于不可变对象,这里看一段源码就清楚了

 1   public String substring(int beginIndex) {
 2         if (beginIndex < 0) {
 3             throw new StringIndexOutOfBoundsException(beginIndex);
 4         }
 5         int subLen = value.length - beginIndex;
 6         if (subLen < 0) {
 7             throw new StringIndexOutOfBoundsException(subLen);
 8         }
 9         return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
10     }

截取函数,直接看第9行代码处,如果beginIndex==0,返回的是当前对象,否则这里是new的一个新对象,其实String中的很多函数都是这样的操作,具体可翻看源码阅读一下。


总结

#1.String类在日常开发中经常使用,但可能对其源码并不是十分了解,通过分析其源码,了解更多看似简单的知识点。

#2.String类的构造函数非常多,需要注意一下,特别是StringBuffer和StringBuilder为入参的构造函数。

#3.String是不可变对象

#4.String#hashCode的计算方式,以31为计算基数。

by Shawn Chen,2019.08.20日,上午。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

在云函数 SCF 里为 Next.js 跑 SSR

很多时候我们都希望首屏速度快,SEO 友好,那么相比于客户端渲染,SSR 渲染将是这方面的优势。Next.js、Nuxt.js 都是 SSR 框架。本篇文章将介绍 Next.js。 通常我们在部署 SSR 的时候,会担心...

腾讯云Serverless
今天
19
0
一文带你初窥软件测试行业

三大原始问题一——软件测试是什么? 在一定条件下对软件系统进行审核、运行、评估,检验软件系统是否满足规定需求或者找出预期结果与实际结果之间的差别。为软件产品的质量和评价提供依据。...

a伟正是在下
今天
17
0
如何避免APK文件的反向工程? - How to avoid reverse engineering of an APK file?

问题: I am developing a payment processing app for Android, and I want to prevent a hacker from accessing any resources, assets or source code from the APK file. 我正在开发适用......

富含淀粉
今天
13
0
python 抓取 微信公众号文章

1、下载 Fiddler 安装 具体操作传送门 2、第一步已完成,入门开始吧 首先确保有微信客户端(推荐PC,移动端会多一些操作) 启动微信、Fiddler ,然后找到需要抓取的公众号(还是关注一下吧,...

acclea
今天
9
0
JS深拷贝

let arr1 = [1, 2, 3, 4, { name: 'hh'}]/浅克隆****/// 1,展开运算符let arr2 = [...arr1]// 2.splicelet arr3 = arr1.splice(0)/深克隆****/// 1.基...

何祯粮
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部