IT知识库 购物 网址 游戏 小说 歌词 快照 开发 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 编程 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> Java -> JDK源码之String、StringBuffer、StringBuilder -> 正文阅读

[Java]JDK源码之String、StringBuffer、StringBuilder

JDK源码之String、StringBuffer、StringBuilder     就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就行了,很多东西实现逻辑都一样,只是底层的实现稍微存在差别,所以导致在性能上有些不同而已。
总体的字符串就分析到这,理解了底层的实现,在日常工作中用得也就更加得心应手了。
以上纯属个人阅读JDK源码的理解,欢迎大虾们指出不对或者补充,同时对于疑惑部分肯定大家赐教,可以评论或者私信,也可以发邮件给我aaddi@sina.com,有什么好的学习方法,也可以随时交流。
欢迎各位IT朋友私信我,相互交流、学习!
             
上一篇文章      下一篇文章      查看所有文章
加:2015-06-10 23:38:30  更:2017-05-15 08:56:28 
 
  Java 最新文章
初入山门,需记门规
java 操作本地数据库 mysql
spring boot 整合 mybatis
单表(SSM、SpringBoot、SpringCloud、Free
Mybatis框架中Mapper动态代理方式
IDEA报错:Error starting ApplicationCont
JDK源码之String、StringBuffer、StringBui
java 初始化与清理
Java 对象初始化
第四天知识点
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 新闻资讯 小游戏 Chinese Culture 股票 三丰软件 开发 中国文化 网文精选 阅读网 看图 日历 万年历 2018年11日历
2018-11-20 2:21:34
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库