我的日常

登录/注册
您现在的位置:论坛 资料库 JAVA开发 > String、StringBuffer、StringBuilder
总共48087条微博

动态微博

查看: 1561|回复: 0

String、StringBuffer、StringBuilder

[复制链接]

326

主题

72

听众

999

金钱

实习版主

该用户从未签到

优秀版主

跳转到指定楼层
楼主
发表于 2015-06-12 13:18:23 |只看该作者 |倒序浏览
就String而言,平时工作中用得最多,但是很多时候还是用不好,有必要对他进行整体的分析下。如果看过Thinking in java,再看下JDK的源码,很多东西就会变得十分明了。现在对String的底层实现进行下分析。

    首先是对构造函数而言,我工作中最常用到的可能就是new String(str)这个构造函数了,所以再在此关注这一个。这个构造函数是对传进来的String进行解析,将其放进一个数组当中,我们设定为arrayOfChar,String类定义了全局变量offset(偏移量),count(大小),value(char类型的数组),此时,会将offset设为0,count设置为arrayOfChar.length,value设置为arrayOfChar,此时整个String构造器完成了初始化工作,三个全局变量全部设定了初始值,当String类型的对象调用类中的方法时,其实就是对这三个变量进行的操作,下面的方法分析中会涉及到。在String的方法中,很多方法返回的都是新的String对象,原因是因为String初始化后,大小就固定了,如下面讲解到的方法SubString、concat等方法。

   常用方法分析:1、最简单的isEmpty,底层也是很简单的一行代码,return this.count == 0,清晰明了,很好的完成了相应的功能。在此,就使用了构造器中的count。

        2、charAt,获取指定下标的字符。之前说过,构造器将String处理成了一个数组,此时要想得到指定下标字符,就很easy了,直接使用数组中的[n]就可以拿到了,不过它加入了偏移量,之前做了简单的异常处理,防止数组越界。

        3、equals将字符串与指定对象的比较,开发中最常用的方法之一。在方法开始,就做了一个判断,如果当前对象和指定对象一样,直接返回true,这里当前对象使用的是this关键字,如果不等于,则进行接下来的操作。当指定对象不是String类型(使用instanceof判断),直接返回false,如果是String类型,则取出当前对象的数组value和指定对象的数组value1,然后根据偏移量对数组进行逐个比较,若数组相等,则返回true,反之有任何一个元素不等,当即返回false。

        4、compareTo将两个字符串按照字典顺序比较。返回负数,0,正数。其实底层实现方式跟equals相似,也是使用数组实现的。但是,他的逻辑却不一样,它会逐个拿到相同下标的数组元素,然后拿到字典顺序进行比较,如果相等,继续,如果不等,直接相减并return,这是就是正数或者负数了,如果全部相等,最后返回0。

        5、startWith(String,int)判断字符串是否是已制定String开始,这里分析带两个参数的,原因是因为startWith(String),endsWith(String)都是调用这个方法实现的,这也进一步展现了代码重用性带来的方便,搞笑、简洁。它的实现依旧是使用数组,将参数String与当前对象数组逐个进行比较,最后得出结果。不过,第二个参数int说明了指定String要从当前对象数组中的哪个下标进行比较。 startWith(String)实际上默认给了startWith(String,int)中int的值为0,表明从数组下标为0的开始比较。endsWith(String)实际就是从数组下标为当前对象数组的长度-指定字符数组的长度进行比较。这样一来,所以的方法最后实现都是startWith(String,int)来实现的。这一点在工作中也应该使用,即代码的重用性,最后上升到代码的简洁。代码虽短(一行到两行),但是却十分完美的实现了其功能,且清晰明了。个人觉得,方法contains也可以使用startWith(String,int)方法来实现,JDK使用indexOf实现的,不过使用startWith需要循环,效率当然会低很多的。【此处我只是举一反三,考虑效率,肯定是indexOf好多了】。

        6、substring(int1,int2)截取字符串,substring(int)调用前一个,不过第二个int2设置为当前对象数组的长度。它表示从下标int1到下标int2的元素取出来,如果缺失int2,默认为数组长度,最后的实现使用的是String的一个构造函数Stirng(int,int,char[])实现的,返回一个新的String对象。在这个构造函数中,对新的String对象初始化了,包括offset,count,value,这样截取的方法就返回了一个符合要求的全新的String对象。

        7、其实还有concat、replace等比较常用的方法,但是,其底层都是针对数组进行的操作,以上讲了几个典型的,这几个就不在一一讲了,可以直接看源码,很容易就理解了。只不过这两个都是返回了全新的String对象,还使用了一些其他的方法,但是思想都差不多一样。其他还有很多常用方法如getChars(char[], int),replaceAll(String, String),split都是调用了相关类的方法,就不在这里讲了。

        8、在String中有个静态内部类CaseInsensitiveComparator,此处还是看下比较好。这个类中只包含了一个方法compare,这个方法是比较连个字符串的,但是忽略其大小写。方法中使用charAt取出对应的数组元素,然后Character.toUpperCase进行转换比较,为了安全,他还使用了Character.toLowerCase进行转换比较,如果相等,进行下一个比较,如果不等,直接求差返回。这个静态内部类中的方法是不能在其他类中方法进行直接访问的,而必须要通过外部类的compareToIgnoreCase方法进行访问。这样做的目的,我个人认为是防止其他类直接访问静态类中的方法,有点类似代理模式,不过这点我还有疑惑,在下面的疑惑中我会提出。这种做法在遍历器中也用到了,不过在遍历器的做法稍有不同,那里的做法是返回内部类的对象,然后利用这个对象去访问内部类中的方法。

        总体来说,String我就理解了这么多,了解了底层怎么实现的,在使用String方法时也就更加得心应手了。看完了底层实现,收获很多,但是也有很多疑惑,先将疑惑列出,希望知道的IT朋友们帮助解答。

            疑惑:1、方法equalsIgnoreCase的实现为return (this == paramString),为什么这样就可以忽略大小写?具体的实现方式是怎么样的?

           2、刚刚提到的内部类,为什么要使用内部类,我直接将内部类的方法设置为private的,然后在相应的方法中调用,也能起到同样的效果,可能是我对内部类不了解,但是为什么要这样做?好处是什么?

            3、hashCode方法给类的全局变量hash赋值了,但是在哪个地方使用到了呢?仅仅赋值而已?会不会跟String的==有关?有的话是什么关系?



续:StringBuffer、StringBuilder:

    其实搞明白了String的相关方法,再回头看StringBuffer和StringBuilder,就会很easy了。其中很多方法的实现都差不多一样的,例如subString方法。之所以StringBuffer是安全的,是因为他的方法都有关键字synchronized,所以速度较慢,很多地方都推荐优先使用StringBuider。其实,看了他们的源码就知道了,他两的实现方式其实都是一样的,很多方法都是调用他们的父类方法AbstractStringBuilder的方法的。其实在这里分析AbstractStringBuilder类更为好,相当于分析了SB和SF两个类的实现。ASB类中的方法主要是insert和append,ASB类的对象不想String那样,大小后期可以动态更改的,原因是ASB维护的是数组,当数组大小不满足的时候,他会扩展数组的大小,不需要重新创建对象。所以说StringBuffer、StringBuilder的初始化以后,大小是可以动态变化的,原因就是底层维护的是数组,可以进行扩展,而不需要新的对象。当然Insert的原理也差不多一样,也是操作数组,所以大小是动态变化的。API文档中给这两个类的定义为:一个可变的字符序列。

    想要弄清楚StringBuffer、StringBuilder,个人觉得弄清了String就行了,很多东西实现逻辑都一样,只是底层的实现稍微存在差别,所以导致在性能上有些不同而已。

总体的字符串就分析到这,理解了底层的实现,在日常工作中用得也就更加得心应手了。

科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、科帮网管理员和版主有权不事先通知发贴者而删除本文


JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

快速回复
您需要登录后才可以回帖 登录 | 立即注册

   

关闭

站长推荐上一条 /1 下一条

发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
快速回复 返回顶部 返回列表