一String源码解析与测试
- String内容是不可变的字符串,String的底层是使用一个不可变的字符数组(final关键词修饰)。
- String类是final类,意味着String类是不可被继承的类,其成员都是final修饰,其方法默认都是被final所修饰。
public final class String
implements java.io.Serializable, Comparable<String>, 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
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
由下面的源码可知,无论是substring,concat等操作,都不是对原先的字符串进行操作,而是重新生成了另一个对象(new)。那么平时你对字符串进行操作的时候都不会改变原先的对象,每次操作都会产生新的对象,所以每次进行字符串拼接都会产生新对象。如果在循环中使用字符串拼接,其代价很高。
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 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);
}
- 深入解析"hello world"和new String(“hello world”)区别
str1和str3在编译期间都会在jvm方法区的运行时常量池中产生字面常量和符号引用(不懂jvm内存结构的可以在我公众号找查找一遍文章叫jvm-运行时数据区的介绍。),运行期间执行str1时"hello world"这个字面常量会被保存在常量池中,执行str3的时候会去常量中查询该字面常量,如果已经存在,则直接引用已存在的字面常量;否则会在常量池中开辟一个空间来存储,并将引用指向该字面常量;所以str1=str3;
str2和str4是通过new产生的对象,new对象是存在堆中,堆中是不管对象内容是否一样,都会开辟一个新空间去存储。所以str2!=str4;
str1和str2有什么不同呢?str1只会在常量池创建一个字面常量;在执行str2的时候除了在堆中new一个对象外,还会在常量池中创建字面常量,平时创建字符串常量时不建议使用str2的方式,这会造成内存的额外开销。
@Test
public void stringTest(){
String str1 = "hello world";
String str2 = new String("hello world");
String str3 = "hello world";
String str4 = new String("hello world
");
System.out.println(str1==str2);//false
System.out.println(str1==str3);//true
System.out.println(str2==str4);//false
}
二Stringbuilder和Stringbuffer
Stringbuilder和StringBuffer都是继承AbstractStringBuilder;StringBuffer多了个synchronized关键字,是线程安全;Stringbuilder线程不安全。
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
三String和StringBuilder
StringBuilder底层是对字符串数组进行操作,在执行期间不会产生新的对象,而前面提到String操作时会产生新对象。
大家有兴趣也可以使用javap命令反编译看看字节码文件。
四String,StringBuilder,StringBuffer何时使用
1不在循环中的字符串,并且字符串拼接少使用String
2在循环中的字符串或者字符串拼接较多使用StringBuilder
3单线程使用StringBuilder,多线程使用StringBuffer。