JDK源码解析基础篇-String、StringBuilder、StringBuffer
来源:互联网 发布:品质退款率被淘宝管控 编辑:程序博客网 时间:2024/06/01 07:40
首先向搞懂常量池的知识点:触摸Java常量池 常量池技术
java.lang包的最后一篇基础篇。搞完这篇就开始集合框架和并发包等内容。Sting、StirngBuilder、StringBuffer的内容很早之前写过 String、StringBuffer和StringBuilder的区别和应用场景 ,但写的太简单了。这次再重新梳理一下这部分内容,留作以后复习。
在 java 语言中, 用来处理字符串的的类常用的有 3 个: String、StringBuffer、StringBuilder。
它们的异同点:
1) 都是 final 类, 都不允许被继承;
2) String 长度是不可变的(内部实现是:private final char value[];), StringBuffer、StringBuilder 长度是可变的(内部也是利用char[]存储实现的);
3) StringBuffer 是线程安全的(通过在方法前面加了synchronized关键字实现的线程同步), StringBuilder 不是线程安全的。
String
String 字符串是常量, 它们的值在创建之后不能够被更改,它在jdk1.7之前是存储在方法区的常量池中的,jdk1.8实现了去永久代,原先的永久代信息放入了元数据区。
String str1 = "abc";String str2 = new String("cde");
上边的两种创建方式,其中第1种是在常量池存储了字符对象char[]a,b,c,然后str1指向了此常量。第二种方式相当于创建了两个string对象,一个是cde本身,另一种是以new关键字在堆中开辟的内存空间。
当利用连接符+来改变字符串常量时,实际上是jdk1.5后jvm利用了StirngBuilder来实现的。当进行下边的代码时:
String str1 = "abc";str1 += "cde";
jvm是采用下图中的方式实现的:
这实际上式jvm对+操作符的重载优化,但是这也有效率问题,当有多个连接符+时,会创建多个StringBuilder。所以对于可变的字符串,一般要采用StringBuilder和StringBuffer来实现。
String方法
string实现的方法有:implements java.io.Serializable, Comparable, CharSequence ,表明它是可序列化,以及重写了compareTo方法。
首先来看它的构造方法:
可以看到,我们可以利用char[],byte[]等来创建字符串对象。
由于String对象的内部是利用char数组来存储的,所以很多方法如length(),isEmpty(),charAt(),equals()等方法都是通过操作char数组来实现的,如:
public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; }
startsWith(prefix) 测试字符串是否是以指定的前缀 prefix 开始, endsWith(suffix) 测试字符串是否是以指定的后缀 suffix 结束
String重写了equals方法和hashCode方法,equals方法比较的是字符对象是否一一相等,其中hashCode方法为:
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
它是针对每一个字符来操作的。为什么选31,可以查看此解释为什么string类的hashCode方法选31作为31位数乘因子 。
indexOf 用于返回指定的子字符串在主字符串中第一次出现处的索引值; lastIndexOf 用于返回指定的子字符串在主字符串中最后一次出现处的索引值。这里并不是采用的经典的字符串匹配算法KMP算法,而是采用的暴力匹配方法。其原因可以查看为什么java String.contains 没有使用类似KMP字符串匹配算法进行优化? 。
subString方法:
public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
string还提供了很多替换和匹配算法:
它是利用正则来实现的,比如:
public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); }
另外,string类还提供了例如:转换大小写,得到char[]数组,getByte方法,valueOf方法。trim()方法,intern方法(此方法与jvm知识有关,后边要看一下)等。字符串操作时我们程序中应用非常多的,jdk为我们做了较好的封装。
StringBuilder、StringBuffer
因为String是不可变的,所以提供了StringBuilder和StringBuffer这两种可变得字符串操作类。两者都实现了AbstractStringBuilder,其内部依然是利用char[]来实现的,不过此char数组是可变的。StringBuilder 与 StringBuffer 支持的所有操作基本上是一致的, 不同的是, StringBuilder 不需要执行同步。同步操作意味着要耗费系统的一些额外的开销, 或时间, 或空间, 或资源等, 甚至可能会造成死锁。从理论上来讲, StringBuilder 的速度要更快一些。下边以StingBuilder方法为例:
其构造方法为:
//默认char[]容量为16 public StringBuilder() { super(16); } //指定容量大小 public StringBuilder(int capacity) { super(capacity); } public StringBuilder(String str) { super(str.length() + 16); append(str); }
append方法:
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); //扩容 满足的最小容量count + len ensureCapacityInternal(count + len); //完成添加 str.getChars(0, len, value, count); count += len; return this; } /** * For positive values of {@code minimumCapacity}, this method * behaves like {@code ensureCapacity}, however it is never * synchronized. * If {@code minimumCapacity} is non positive due to numeric * overflow, this method throws {@code OutOfMemoryError}. */ private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { //返回新容量的char[] value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }//返回新的char[] public static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } * @param srcBegin index of the first character in the string * to copy. * @param srcEnd index after the last character in the string * to copy. * @param dst the destination array. * @param dstBegin the start offset in the destination array. * @exception IndexOutOfBoundsException If any of the following * is true: * <ul><li>{@code srcBegin} is negative. * <li>{@code srcBegin} is greater than {@code srcEnd} * <li>{@code srcEnd} is greater than the length of this * string * <li>{@code dstBegin} is negative * <li>{@code dstBegin+(srcEnd-srcBegin)} is larger than * {@code dst.length}</ul> */ public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); }
扩容的方法最终是由newCapacity()实现的,在这个方法中首先把容量扩大为原来的容量加2,如果此时仍小于指定的容量,那么就把新的容量设为minimumCapacity(原来的长度+添加的字符串长度)。然后判断是否溢出,如果溢出了,把容量设为Integer.MAX_VALUE。最后把value值进行拷贝,这显然是耗时操作。然后采用的字符拷贝操作。
append()是最常用的方法,它有很多形式的重载。上面是其中一种,用于追加字符串。如果str是null,则会调用appendNull()方法。这个方法其实是追加了’n’、’u’、’l’、’l’这几个字符。如果不是null,则首先扩容,然后调用String的getChars()方法将str追加到value末尾。最后返回对象本身,所以append()可以连续调用。
复制是最后调用的System的native方法实现的:
* @param src the source array. * @param srcPos starting position in the source array. * @param dest the destination array. * @param destPos starting position in the destination data. * @param length the number of array elements to be copied. * @exception IndexOutOfBoundsException if copying would cause * access of data outside array bounds. * @exception ArrayStoreException if an element in the <code>src</code> * array could not be stored into the <code>dest</code> array * because of a type mismatch. * @exception NullPointerException if either <code>src</code> or * <code>dest</code> is <code>null</code>. */ public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
字符串翻转:
public AbstractStringBuilder reverse() { boolean hasSurrogates = false; int n = count - 1; for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; char cj = value[j]; char ck = value[k]; value[j] = ck; value[k] = cj; if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } } if (hasSurrogates) { reverseAllValidSurrogatePairs(); } return this; }
toString()方法返回一个字符串:
@Override public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }
- JDK源码解析基础篇-String、StringBuilder、StringBuffer
- 【JDK】:java.lang.String、StringBuilder、StringBuffer 源码解析
- JDK源码解析之StringBuilder和StringBuffer
- String、StringBuilder、 StringBuffer 深入分析 源码解析
- String、StringBuilder、 StringBuffer 深入分析 源码解析
- 源码角度解析:StringBuffer、StringBuilder、String
- Java String、StringBuffer、StringBuilder源码解析
- 基础篇--StringBuffer、StringBuilder、String
- string、StringBuffer、StringBuilder解析
- String StringBuffer StringBuilder 基础
- JDK 1.7源码阅读笔记(一)String,StringBuilder,StringBuffer
- String系列——StringBuilder & StringBuffer关键源码解析
- String,StringBuffer和StringBuilder源码解析[基于JDK6]
- String,StringBuffer,StringBuilder性能比较,线程安全测试,源码解析。
- 从源码解析Java中String、StringBuilder、StringBuffer的区别
- String、StringBuffer、StringBuilder源码比较
- String、StringBuilder、StringBuffer全面解析
- String&&StringBuffer&&StringBuilder深层次解析
- 3 eclipse安装插件的三种方式
- 2017年08月01日
- angularjs-1.3代码学习 模块
- hdu 5631 Rikka with Graph【并查集】
- DevOps更多的是种文化!
- JDK源码解析基础篇-String、StringBuilder、StringBuffer
- 走进java_了解ArrayList和LinkedList
- 理解HTTP之Content-Type
- python学习-面向对象进阶之闭包(八)
- 程序员最憋屈的事情是什么
- pyhton微博爬虫(1)——获取知乎官方账号的微博数据
- LINQ系列:LINQ to SQL Where条件
- javaHL(JNI) Not Available解决办法
- cordova-plugin-app-version插件的使用