https://www.cnblogs.com/xiaoxi/p/6036701.html
String类
String类的源码:
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; /** * Class String is special cased within the Serialization Stream Protocol. * * A String instance is written into an ObjectOutputStream according to * <a href="{@docRoot}/../platform/serialization/spec/output.html"> * Object Serialization Specification, Section 6.2, "Stream Elements"</a> */ private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
String类是不可变的(final类,不能被继承)
创建字符串
public class StringTest { public static void main(String[] args){ String str1 = "abc"; //单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中; char a[] = {'n',' ','i','c','e'}; /*public String(char value[], int offset, int count) * 提取字符数组a中的一部分创建一个字符串对象*/ String str2 = new String(a, 2, 3); /*public String(char value[]) * 用字符数组a创建一个字符串对象*/ String str3 = new String(a); String str4 = new String("new String"); //使用new String("")创建的对象会存储到heap中,是运行期新创建的; System.out.println(str1 + " " + str2 + " " + str3 + " " + str4); } }
运行结果:
abc
ice
n ice
new String
字符串常量池
每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。
由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
String a = "chenssy";
String b = "chenssy";
String c = new String("chenssy"); //new关键字一定会产生一个对象chenssy,但是这个对象时存储在对内存中。
但Java中不存在两个一模一样的字符串对象,所以,堆中的chennsy应该是引用字符串常量池中的chenssy。
/** * 编译期确定 */ public void test3(){ String s0="helloworld"; String s1="helloworld"; String s2="hello"+"world"; System.out.println("===========test3============"); System.out.println(s0==s1); //true 可以看出s0跟s1是指向同一个对象 System.out.println(s0==s2); //true 可以看出s0跟s2是指向同一个对象 }
/** * 编译期无法确定 */ public void test4(){ String s0="helloworld"; String s1=new String("helloworld"); String s2="hello" + new String("world"); System.out.println("===========test4============"); System.out.println( s0==s1 ); //false System.out.println( s0==s2 ); //false System.out.println( s1==s2 ); //false }
/** * 继续-编译期无法确定 */ public void test5(){ String str1="abc"; String str2="def"; String str3=str1+str2; System.out.println("===========test5============"); System.out.println(str3=="abcdef"); //false }
JVM对String str="abc"对象放在常量池中是在编译时做的,而String str3=str1+str2是在运行时刻才能知道的。new对象也是在运行时才做的。
/** * 编译期优化 */ public void test6(){ String s0 = "a1"; String s1 = "a" + 1; System.out.println("===========test6============"); System.out.println((s0 == s1)); //result = true String s2 = "atrue"; String s3= "a" + "true"; System.out.println((s2 == s3)); //result = true String s4 = "a3.4"; String s5 = "a" + 3.4; System.out.println((s4 == s5)); //result = true }
/** * 编译期无法确定 */ public void test7(){ String s0 = "ab"; String s1 = "b"; String s2 = "a" + s1; System.out.println("===========test7============"); System.out.println((s0 == s2)); //result = false }
/** * 比较字符串常量的“+”和字符串引用的“+”的区别 */ public void test8(){ String test="javalanguagespecification"; String str="java"; String str1="language"; String str2="specification"; System.out.println("===========test8============"); System.out.println(test == "java" + "language" + "specification"); //true System.out.println(test == str + str1 + str2); //false }
对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"I"+"love"+"java"; 的字符串相加,在编译期间便被优化成了"Ilovejava"。对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。