首先了解字符串常量池的设计思想:
字符串的分配和其他的对象分配一样,需要耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串会极大程度地影响程序的性能。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化:
1)为字符串开辟一个字符串常量池,类似于缓存区。
2)创建字符串常量时,首先坚持字符串常量池是否存在该字符串。
3)存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。
实现的基础:
1)实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享。
2)运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。
在创建字符串的时候,通过直接赋值(String a="a")创建的对象是保存在常量池中,通过String a=new String("a")创建的对象是保存在堆内存中,主要是返回指向对象的句柄的不同(具体可以查询句柄、引用、对象的关系)
除此之外在new String(XXX)在创建的时候过程会存在这样的情况,如果XXX不存在在常量池中,则创建XXX保存在常量池,这样就生成两个对象,一个在堆,一个在常量池
但是存在以下情况String c=new String("a")+new String("b"),在常量池中是不存在“ab”这么个对象的,在这里可以使用c.intern()将c对象保存到常量池中去。
回到正题了,下面是一些字符串比较的例子和说明:
1 public void StringTest(){ 2 3 //编译期可确定值的常量就是编译期常量,即被final修饰的字符串变量,final String a = "12",a也是编译器常量。String b = "34",因为不是final的所以不是编译期常量。 4 //字符串属于引用数据类型。对于引用类型,==是地址值的比较
//主要是编译器是否对语句进行优化 5 6 String s1="1234"; 7 //对于两个编译期常量字符串相加,编译器会进行优化,直接优化成"1234",所以不会在字符串常量池中创建"12","34"这两个字符串对象,而只会创建一个"1234"字符串对象。 8 String s2="12"+"34"; 9 System.out.println(s1==s2); 10 11 //对象保存在堆内存中,所以肯定不相等 12 String s3=new String("1234"); 13 System.out.println(s1==s3); 14 15 //s4+"34"在运行期,相加的结果是生成一个新的字符串对象放置在堆内存中 16 String s4="12"; 17 String s5=s4+"34"; 18 System.out.println(s1==s5); 19 20 //引用不变,但是还是指向了在堆内存中的字符串对象 21 String s6="12"; 22 s6+="34"; 23 System.out.println(s1==s6); 24 25 //substring和replace出来的都是新的字符串,即使常量池中存在截取后的或者替换后的字符串,==也不相等。 26 String s7="123456".substring(0,4); 27 System.out.println(s1==s7); 28 29 //堆对象+创建的对象依然是堆对象 30 String s8="12"; 31 String s9="34"; 32 String s10=s8+s9; 33 System.out.println(s1==s10); 34 35 //s11被修饰成编译期常量了,相当于s12=“12”+“34”,会被编译器优化 36 final String s11="12"; 37 String s12=s11+"34"; 38 System.out.println(s1==s12); 39 40 //这种方式还是创建成堆对象 41 String s13=new String("12"); 42 String s14=s13+"34"; 43 System.out.println(s14==s1); 44 45 46 //这是intern作用的例子,堆对象调用inter会将自身放到字符常量中 47 String b=new String("9")+new String("9"); 48 b.intern(); 49 String a="99"; 50 System.out.println(a==b); 51 52 String c=new String("19")+new String("19"); 53 String d="99"; 54 System.out.println(c==d); 55 56 }