最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西。其实,JDK的源码是越读越有味的。下面总结一下我读这些源码的收获吧。

注意:虽然源码的版本是JDK6,但是个人觉得学习这个版本的源码对于理解数据结构非常有帮助,因为String就是一个数据结构,它是char []的封装,实现了很多对char []的操作

第一部分:String源码解析

(1)String实现了CharSequence接口,这个接口的方法不多,就下面几个:

1
2
3
4
intlength();
charcharAt(intindex);
CharSequence
subSequence(intstart,intend);
publicStringtoString();

关于“接口”的深刻理解,等抽空再写出来吧。我个人感觉,“接口”这个名称很容易让人产生误解的,不利于面向接口编程。面向对象编程是语言设计上的一个壮举,实现了子类继承父类这样类似生物学的完美逻辑,但是接口概念的提出,彻底颠覆了类和对象的观念,抛弃了类和对象的观念,将思维的灵活性推向了极致。

(2)String的成员变量

1
2
3
privatefinalcharvalue[];
privatefinalintoffset;
privatefinalintcount;

final修饰一个成员变量(属性),必须要显示初始化。通常有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。其实,从数据结构的角度来看,String就是一个数据结构,它是char []的封装,具体的属性包括:char [] value,存放字符;offset表示偏移量,count表示char的数量。value.length和count还是有区别的,这一点在AbstractStringBuilder类的体现的更明确。

(3)和StringBuffer,StringBuilder的关系:

1
2
3
4
5
6
7
8
9
10
publicString(StringBuffer
buffer)
{
    synchronized(buffer)
    {
      this.value=Arrays.copyOf(buffer.getValue(),buffer.length());}
}
publicString(StringBuilder
builder)
{
    this.value=Arrays.copyOf(builder.getValue(),builder.length());
}

对于StringBuffer而言,处处要考虑其在多线程环境下的并发问题。需要注意是Arrays.copyOf()方法。这个方法的具体实现如下所示:

1
2
3
4
5
6
7
publicstaticchar[]copyOf(char[]original,intnewLength)
{
        char[]copy=newchar[newLength];
,
                        
Math.min(original.length,newLength));
        returncopy;
    }

此方法的泛型重载为:

1
2
3
4
publicstatic<T>T[]copyOf(T[]original,intnewLength)
{
    return(T[])copyOf(original,newLength,original.getClass());
}

而copyOf(original,

newLength, original.getClass());的具体实现如下:

1
2
3
4
5
6
7
8
9
publicstatic<T,U>T[]copyOf(U[]original,intnewLength,Class<?extendsT[]>newType)
{
        T[]copy=((Object)newType==(Object)Object[].class)
            ?(T[])newObject[newLength]
            :(T[])Array.newInstance(newType.getComponentType(),newLength);
,
                        
Math.min(original.length,newLength));
        returncopy;
}

【注】对于上面的泛型方法,建议深刻的理解,其中T[]表示函数的返回值,<T,U>表示函数的参数类型。为什么这样写呢?这属于泛型的知识范围了,本文不再深究,如果对此处泛型内容感兴趣,请等待后续文章。

(4)trim方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
publicStringtrim()
{
intlen=count;
;
intoff=offset;      /*
avoid getfield opcode */
char[]val=value;    /*
avoid getfield opcode */
while((st<len)&&(val[off+st]<='
'))
{
    st++;
}
]<='
'))
{
    len--;
}
)||(len<count))?substring(st,len):this;
}

avoid getfield opcode是基于效率考虑的,String对象是在堆中生成的,所以将offset和value取出来放在off和val临时变量上,效果更好。类似,js中的对象链一样。

(5)intern方法,可以看JDK的描述,讲解的非常透彻:

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String  object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to
this String object is returned.

It follows that for any two strings s and t, s.intern()==t.intern() is true if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned. 

字符串常量池,初始值为空,它由类String类独自维护。

当调用intern 方法时,如果池中已经包含一个等于此String 对象的字符串(是否相等由 equals(Object)方法确定),则返回池中的字符串引用。否则,将此 String 对象添加到池中,并且返回此String 对象的引用。例如:对于任何两个字符串s和t,当且仅当s.equals(t)为true时,s.intern()==t.intern()才为true。

所有字面值字符串和字符串赋值常量表达式都是intern实现的。

【注】关于字符串常量,网上的内容很多,各种观点都有,看起来有点可笑,其实,看看这段JDK的注释,所有的疑问都消失了。如果对此内容有疑问,想讨论讨论请加群再细说吧,联系方式见本文末尾。

(6)startsWith方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
publicbooleanstartsWith(Stringprefix)
{
);
}
publicbooleanendsWith(Stringsuffix)
{
returnstartsWith(suffix,count-suffix.count);
}
 
publicbooleanstartsWith(Stringprefix,inttoffset)
{
charta[]=value;
intto=offset+toffset;
charpa[]=prefix.value;
intpo=prefix.offset;
intpc=prefix.count;
// Note: toffset might be near -1>>>1.
)||(toffset>count-pc))
{
    returnfalse;
}
)
{
    if(ta[to++]!=pa[po++])
{
        returnfalse;
    }
}
returntrue;
}

此函数对自增自减使用的非常好,可以参考参考。在此不再赘述。

第二部分:AbstractStringBuilder源码解析

StringBuffer,StringBuilder的关系都是继承于AbstractStringBuilder,所以先从它入手分析。

(1)成员变量:

1
2
charvalue[];
intcount;

无offset偏移量,字符都是从value数组的0位置开始的。

(2)capacity方法:

返回的value.length,表示可以存储的空间。

(3)扩容方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
voidexpandCapacity(intminimumCapacity)
{
;
)
        {
            newCapacity=Integer.MAX_VALUE;
        }elseif(minimumCapacity>newCapacity)
        {
    newCapacity=minimumCapacity;
}
charnewValue[]=newchar[newCapacity];
,count);
value=newValue;
}

(4)补长或者截断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
publicvoidsetLength(intnewLength)
{
)
    thrownewStringIndexOutOfBoundsException(newLength);
if(newLength>value.length)
    expandCapacity(newLength);
if(count<newLength)
        {
    for(;count<newLength;count++)
value[count]='\0';
}else
         {
            count=newLength;
         }
}

(5)瘦身

1
2
3
4
5
6
7
8
9
publicvoidtrimToSize()
{
        if(count<value.length)
        {
            char[]newValue=newchar[count];
,count);
            this.value=newValue;
         }
}

需要注意的方法是:

public static native void arraycopy(Object src, int  srcPos, Object dest, int destPos, int length);很常用的方法啊。

最后想说的一点是,由于时间的原因,JDK部分的源码分析只能到此结束,虽然有部分内容没有深入挖掘,例如泛型部分,常量池部分等,但是只能到此了。源码分析涉及的内容很多,而本文只找了些重点部分进行介绍。如果对本部分内容有异议或者想了解更多请加群:278721352,入群方式为:

声明: 本文由金丝燕网原创编译,转载请保留链接: String,StringBuffer和StringBuilder源码解析[基于JDK6]

String,StringBuffer和StringBuilder源码解析[基于JDK6]的更多相关文章

  1. String、StringBuffer和StringBuilder源码解析

    1.String 1.1类的定义 public final class String implements java.io.Serializable, Comparable<String> ...

  2. [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析

    String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识,  ...

  3. String、StringBuffer、StringBuilder源码分析

    利用反编译具体看看"+"的过程 1 public class Test 2 { 3 public static void main(String[] args) 4 { 5 int ...

  4. Stringbuffer与Stringbuilder源码学习和对比

    >>String/StringBuffer/StringBuilder的异同 (1)相同点观察源码会发现,三个类都是被final修饰的,是不可被继承的.(2)不同点String的对象是不可 ...

  5. String、StringBuffer、StringBuilder源码解读

    序 好长时间没有认真写博客了,过去的一年挺忙的.负责过数据库.线上运维环境.写代码.Code review等等东西挺多. 学习了不少多方面的东西,不过还是需要回归实际.加强内功,方能扛鼎. 去年学习M ...

  6. StringBuffer 和Stringbuilder源码分析

    首先看一下他们的继承关系   这个两个对象都继承了AbstractStringBuilder抽象类.   1.他们的实现方式都一样的,唯一区别的StringBuffer在多线程的时候是保证了数据安全, ...

  7. 【Java并发集合】ConcurrentHashMap源码解析基于JDK1.8

    concurrentHashMap(基于jdk1.8) 类注释 所有的操作都是线程安全的,我们在使用时无需进行加锁. 多个线程同时进行put.remove等操作时并不会阻塞,可以同时进行,而HashT ...

  8. String的equals()方法源码解析

    每个String对象在创建的时候都构造了一个char类型的final声明的不可替换数组,数组中的每一个元素即字符串对应的每一个字符如图: String的equals()在比较的时候会进行两步比较: 1 ...

  9. Spring源码解析-基于注解依赖注入

    在spring2.5版本提供了注解的依赖注入功能,可以减少对xml配置. 主要使用的是 AnnotationConfigApplicationContext: 一个注解配置上下文 AutowiredA ...

随机推荐

  1. Elasticsearch Java Api--DeleteByQuery

    一.安装插件 要删除某个索引的一个type下的所有文档,相当于关系型数据库中的清空表操作.查阅了一些资料可以通过Delete-by-Query插件删除,首先使用插件管理器安装Delete-by-Que ...

  2. iOS9/iOS8界面对比 XCode7

    Xcde7 bate 无需开发这账号(99¥)可以调试程序 目前是测试版 iOS9/iOS8界面对比 (注:左边为iOS8界面,右边为iOS9界面.) 1.新字体 苹果在 iOS9 中使用旧金山字体取 ...

  3. Installing Cygwin and Starting the SSH Daemon

    This chapter explains how to install Cygwin and start the SSH daemon on Microsoft Windows hosts. Thi ...

  4. Visual Studio 2013 Update 2 and with Update 2

    Microsoft 的开发工具 Visual Studio 2013 迎来 Update2 更新.本次更新将为普通开发者带来更多全新功能.修复之前旧版 Bugs.提升性能以及稳定性.之前已经安装 VS ...

  5. What am I missing out in life if I don't have a girlfriend?

    http://www.quora.com/What-am-I-missing-out-in-life-if-I-dont-have-a-girlfriend/answer/Kelly-Erickson ...

  6. java基础-004

    ---恢复内容开始--- 14.Java集合类框架的基本接口 集合类接口指定了一组叫做元素的对象.集合类接口的每一种具体的实现类都可以选择以它自己的方式对元素进行保存和排序.有的集合类允许重复的键,有 ...

  7. poj2193

    //Accepted 368K 532MS //线性dp //dp[i][j]表示前i位最后一个是j的排列数 //dp[i][j]=sum(dp[i-1][h]) h*2<=j #include ...

  8. a various of context

    ContextWrapper.getApplicationContext():Return the context of the single, global Application object o ...

  9. 深入分析:Fragment与Activity交互的几种方式(三,使用接口)

    第一步:我们需要在Fragment中定一个接口,并确保我们的容器Activity实现了此接口: public interface onTestListener { public void onTest ...

  10. iOS App 转移

    此文章只是为了记录一个Apple ID下的APP,转移到另外一个Apple ID 账户下.为了说的清楚下面用A账户(有App,要转出去)B账户(接收A账户App,接收者),来说明. 1.      登 ...