今年终于重新回到开发岗位继续我的程序员生涯,但时隔一年半,很多都有些生疏了,仔细读了一遍<Thinking In Java>,发现很多基本技术和思想其实从一开始就没研究明白。决定重新对照着书本,jdk和源码把Java中基本的类库研读总结下。
第一篇就先从最简单最基本的String开始吧!
博客的对代码的排版似乎不好,附件里附上txt格式的内容,可读性会好些。
1.String的基本特性
我们在class中找到java.lang.String,先来看String的基本特性。
String类的定义是这样的:public final class String implements java.io.Serializable, Comparable<String>, CharSequence
从以上定义,我们可以看出String的几个基本特性:
·String是一个类。(似乎是废话。主要与其他基本类型分开,Java中的类型似乎只有String与Enum是类形式定义的。)
·String是只读的常量,具有不可变性;不可被继承。(修饰为final)
·String类型是可序列化的,可比较的字符序列。(implements java.io.Serializable, Comparable<String>, CharSequence)
再来看一下Sting类中的定义的几个基本field
private final char value[];//String的值,String的本质就是char型数组
private final int offset;//子数组第一个字符的索引
private final int count;//字符串中的字符数量
private int hash; //对象的hash code
经过上面的分析,其实我们已经能看出String对象的本质是一个经过封装的char型数组,封装后提供了一些方便操作的方法。
2.Sting常用方法及实现(大部分注释选自JavaSE5中文API说明)
2.1.equals(Object anObject)
/**
* 重写equals方法 比较此字符串与指定的对象。
* 当且仅当该参数不为 null,并且是表示与此对象相同的字符序列的 String对象时,结果才为true。
* @param anObject 与此 String 进行比较的对象。
* @return 如果 String 相等,则返回 true;否则返回 false。
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {// 先判断类型
String anotherString = (String) anObject;
int n = count;
if (n == anotherString.count) {// 再判断数组容量是否相同
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {// 再遍历判断每一个字符
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
2.2.compareTo(String anotherString)方法
/**
* 重写compreTo方法 按字典顺序比较两个字符串。 该比较基于字符串中各个字符的 Unicode 值。 将此 String
* 对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此 String 对象在参数字符串之前,则比较结果为一个负整数。
* 如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。 如果这两个字符串相等,则结果为 0;compareTo
* 只有在方法 equals(Object) 返回 true 时才返回 0。 这是字典排序的定义。
* 如果这两个字符串不同,则要么它们在某个索引处具有不同的字符,该索引对二者均为有效索引;要么它们的长度不同;或者同时具备上述两种情况。
* 如果它们在一个或多个索引位置上具有不同的字符,
* 假设 k 是这类索引的最小值;则按照 < 运算符确定的那个字符串在位置 k上具有较小的值,其字典顺序在其他字符串之前。
* 这种情况下,compareTo 返回这两个字符串在位置 k 处的两个不同的 char 值,即值:
* this.charAt(k)-anotherString.charAt(k)
* 如果它们没有不同的索引位置,则较短字符串在字典顺序上位于较长字符串的前面。 这种情况下,compareTo 返回这两个字符串长度的不同,即值:
* this.length()-anotherString.length()
* @param anotherString 要比较的 String。
* @return 如果参数字符串等于此字符串,则返回 0 值;
* 如果按字典顺序此字符串小于字符串参数,则返回一个小于 0 的值;
* 如果按字典顺序此字符串大于字符串参数,则返回一个大于 0 的值。
*/
public int compareTo(String anotherString) {
int len1 = count;
int len2 = anotherString.count;
int n = Math.min(len1, len2);// 获得两个字符串中较短的长度
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
/* 在一个或多个索引位置上具有不同的字符 */
if (i == j) {// 偏移量相同
int k = i;
int lim = n + i;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
} else {
while (n-- != 0) {
char c1 = v1[i++];
char c2 = v2[j++];
if (c1 != c2) {
return c1 - c2;
}
}
}
/* 没有不同的索引位置 */
return len1 - len2;
}
前面的注释中,已经把String的排序规则说的很明白了。简单来说就是:1.先判断每个索引处的字符都相同,找到第一个字符不同处的索引,返回此索引处两个字符的差;2.如果每个索引处的字符都相同,判断两个数组的长度,返回两个字符串的长度差。
2.3.startsWith(String prefix, int toffset)
/**
* 测试此字符串是否以指定前缀开始,该前缀以指定索引开始。
* @param prefix 前缀
* @param toffset 在字符串中开始查找的位置。
* @return 如果该参数表示的字符序列是此对象从索引 toffset 处开始的子字符串,则返回 true;否则返回 false。
* 如果 toffset 为负或大于此 String 对象的长度,则结果为 false;否则结果与该表达式的结果相同。
*/
public boolean startsWith(String prefix, int toffset) {
char ta[] = value;
int to = offset + toffset;
char pa[] = prefix.value;
int po = prefix.offset;
int pc = prefix.count;
// Note: toffset might be near -1>>>1.
if ((toffset < 0) || (toffset > count - pc)) {
return false;
}
while (--pc >= 0) {//遍历前缀的字符,与当前字符串进行比较
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
这个方法的实现很简单,需要注意的就是toffset的值不要为负或者大于String对象的长度。
2.4.String substring(int beginIndex, int endIndex)
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value);
}
很常用的一个方法,会截取从beginIndex处到endIndex处的字符串,生成一个新的字符串。从方法实现可以看出,要注意的有两点:1.beginIndex和endIndex两个参数要符合要求,否则会抛出StringIndexOutOfBoundsException。2.截取的字符串包括beginIndex处的字符,不包括endIndex处的字符。
2.5.String trim()
/**
* 返回字符串的副本,忽略前导空白和尾部空白。
* 如果此 String 对象表示一个空字符序列,或者此 String 对象表示的字符序列的第一个和最后一个字符的代码都大于 '\u0020'(空格字符),
* 则返回对此 String 对象的引用。
* 否则,若字符串中没有代码大于 '\u0020' 的字符,则创建并返回一个表示空字符串的新的 String 对象。
* 否则,假定 k 为代码大于 '\u0020' 的第一个字符的索引,m 为代码大于 '\u0020' 的最后一个字符的索引。
* 创建一个新的 String 对象,它表示此字符串中从索引 k 处的字符开始,到索引 m 处的字符结束的子字符串,也就是 this.substring(k, m+1) 的结果。
* 此方法用于截去字符串从头到尾的空白(如上面所定义)。
* @return 此字符串移除了前导和尾部空白的副本,如果没有前导和尾部空白,则返回此字符串。
*/
public String trim() {
int len = count;
int st = 0;
int off = offset;
char[] val = value;
while ((st < len) && (val[off + st] <= ' ')) {
st++;
}
while ((st < len) && (val[off + len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < count)) ? substring(st, len) : this;
}
另一个常用的方法,去除空字符串。可以看到,这个方法的实现就是定位到非空字符串的索引处,然后调用substring方法截取字符串中的非空字符串。(Sun的工程师写代码真是简洁,但读起来有点累啊~)
2.6.String valueOf()
我们经常使用String.valueOf()方法将基本类型转换为String型,其中的操作也很简单,就是调用了基本类型的包装类中的toString()方法。比如
public static String valueOf(float f) {
return Float.toString(f);
}
3.String的几点使用须知
3.1.String的不变性。String对象是不可变的,只读的,任何对他的引用都无法改变他的值。我们从上面看的几个String内置方法的实现也可以看出,任何需要改变字符串内容的方法,实际在实现时都是创建了新的String对象作为返回值,而不是改变原有的String对象。(比如substring,trim)
3.2.String和StringBuilder(StringBuffer)的区别。这是个老生常谈的问题了,在频繁调用的循环中,StringBuilder无疑是有优势的(tips:如果能预先估算字符串的上限,那么预先为StringBuilder分配空间大小是提高效率的好办法),但是正常的简单拼接中,使用String的"+"和"+="真的没有想象的那么“效率低下”,因为编译器会自动调用StringBuilder来帮你实现。如果只是String newString = oldString + "test"这样的语句的话,那么真的没有必要使用StringBuilder实现,在大多数情况下,让“人”舒服比让“机器”舒服更为重要。
3.3.String的对象引用机制。每个字符串都会在内存中分配地址,String对象实际上是对内存中字符串的引用。比如我们现在有个String a = "a";那么当我们创建一个新的String对象String b = new String("a");时,并没有在内存中分配新的空间来再存储"a",而是将b的引用也指向了原来"a"在内存中的位置。同样的,当没有对象引用指向"a"时,垃圾回收器会对他进行接管。
分享到:
相关推荐
5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5.java系统类库.zip5....
基于java的开发源码-FAT文件系统读写类库 fat32-lib.zip 基于java的开发源码-FAT文件系统读写类库 fat32-lib.zip 基于java的开发源码-FAT文件系统读写类库 fat32-lib.zip 基于java的开发源码-FAT文件系统读写类库 ...
基于java的开发源码-FTP客户端Java类库 ftp4j.zip 基于java的开发源码-FTP客户端Java类库 ftp4j.zip 基于java的开发源码-FTP客户端Java类库 ftp4j.zip 基于java的开发源码-FTP客户端Java类库 ftp4j.zip 基于java的...
1.功能:该API为适用于Java平台下,通过后端程序代码调用API接口操作PDF文档,可实现如下功能: 1.1 文档转换:PDF转图片/Word/SVG/XPS/HTML/XPS/TIFF、图片转PDF 1.2 文档操作:文档创建、合并、拆分、压缩、复制...
免费Java Excel类库_Free Spire.XLS for Java_2.2.0
类库开发的设计准则.doc 类库开发的设计准则.doc 类库开发的设计准则.doc 类库开发的设计准则.doc 作用我就不说了,需要的人下
自己的Java工具类库 + 主体项目测试.zip
031115_【第11章:Java常用类库】_正则表达式.rar
java2类库17[整理].pdf
基于java的开发源码-图像处理类库 Java Image Filters.zip 基于java的开发源码-图像处理类库 Java Image Filters.zip 基于java的开发源码-图像处理类库 Java Image Filters.zip 基于java的开发源码-图像处理类库 ...
java类库java类库
一个牛逼的 Java 字节码类库!(csdn)————程序
.NET Framework 类库参考手册(Microsoft. 部分 A to M )[微软官方 MSDN] MSDN Library - .NET Development - .NET Framework 3.5 - .NET Framework 类库 制作成了chm格式,方便离线状态下学习! 剩余部分在整理...
大漠类库生成工具v21.0 .
Java教学课件PPT
大漠类库工具,可生成各种语言的模块,易语言大漠类库自动生成工具,易语言大漠类库自动生成工具,易语言大漠类库自动生成工具,易语言大漠类库自动生成工具
Java2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rarJava2 类库.rar
Android源码——图表生成类库_new_39.zip