String 基础
String源码
public final class String
implements java.io.Serializable, Comparable, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence. Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.value = "".value;
}
...
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
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);
}
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
}
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
分析源码:
1.String 类为 final 修饰,说明该类不能被重写。 2.String类型的字符串其实是以 字符的形式存储的,(private final char value[]) 3.任何操作字符串的方法都是建立在新的字符串之上的,字符串的操作不会影响到原来的字符串对象,而是新建一个字符串副本以供操作。
String & StringBuilder&StringBuffer
String
String s1 = "daxiong"; String s2 = "daxiong"; String s3 = new String("daxiong"); String s4 = new String("daxiong");
JVM 内存机制中针对不同的属性进行不同的分区存储。字面量以及符号都会存在于方法区的常量池中,这里以HotSpot虚拟机为例,那么 String s1 = "daxiong"; 其中 "daxiong" 字面量就会存储到方法区的常量池中,当执行到 Stirng s2 = "daixong";的时候虚拟机会到方法区的常量池中进行检测,如果检测到常量池中存在"daxiong",那么就不会再次创建,如果没有检测到,则会重新创建,这里很显然已经存在,则不会再次创建新的"daxiong"。而对于String s3 = new String("daxiong");JVM专门分配一块内存区域叫做堆来存储对象实例,也就是通过new关键字创建的对象(注意:随着技术的发展,当前的虚拟机不是所有的通过new关键字创建的实例都会放到堆中),那么s3这个实例对象就会在堆上被分配内存空间,当然String s4 = new String("daixong");也同样会在堆上被分配内存空间。而这两者的引用都会存储到栈空间,栈空间又分为JVM虚拟机栈和本地方法栈两类,上面的实例的引用都在JVM虚拟机栈中存储。所以综上所述:s1 == s2,s1 != s3/s4,s3 != s4;
StringBuilder
String s = "hello";
for(int i = 0;i < 1000;i++){
s += "world";
}
上面这段代码是通过String直接操作的,那么根据之前分析的String的特性可知:每执行一步 "+" 操作,需要先创建一个新的对象,然后将原对象赋值给新对象,然后在新对象上进行 "+"操作,然后再将新对象返回。以此类推...,执行完上面的代码需要创建 1000 个新对象,很浪费空间。
StringBuilder sb = new StringBuilder("hello");
for(int i = 0;i < 1000;i++){
sb.append("world");
}
上面这段代码只会创建一个对象,即StingBuilder,它的操作字符串效果是在原对象上进行的,不会浪费太多空间。
StringBuffer
通过查看源码发现StringBuilder 和 StringBuffer的成员变量和方法大致相同,只不过StringBuffer 在方法上加入了同步关键字:synchronized,也就是说StringBuffer提供了多线程访问线程安全策略,是线程安全的。那么从这里可知:
StringBuilder 执行效率快,线程不安全;StringBuffer执行慢,线程安全。