public static void main(String [] args) {
String s1 = "Programming";
String s2 = new String("Programming");
String s3 = "Program";
String s4 = "ming";
String s5 = "Program" + "ming";
String s6 = s3 + s4;
System.out.println(s1 == s2);//false
System.out.println(s1 == s5);//true
System.out.println(s1 == s6);//false
System.out.println(s1 == s6.intern());//true
System.out.println(s2 == s2.intern());//false
}
注:
- String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。
- 每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串
- 字符串+操作其本质是创建了StringBuilder对象进行append操作,然后将拼接后的StringBuilder对象用toString方法处理成String对象
- 一个初始为空的字符串池,它由类String独自维护。当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。
它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
第一个
System.out.println(s1 == s2);//false
new关键字会产生一个对象,JVM首先在字符串池中查找有没有"Programming"这个字符串对象,如果有,则不在池中再去创建"Programming"这个对象了,直接在堆中创建一个"Programming"字符串对象,然后将堆中的这个"Programming"对象的地址返回赋给引用s2,这样,s2就指向了堆中创建的这个"Programming"字符串对象;如果没有,则首先在字符串池中创建一个"Programming"字符串对象,然后再在堆中创建一个"Programming"字符串对象,然后将堆中这个"Programming"字符串对象的地址返回赋给s2引用,这样,s2指向了堆中创建的这个"Programming"字符串对象。当执行 System.out.println(s1 == s2);//false时, 因为采用new关键字创建对象时,每次new出来的都是一个新的对象,也即是说引用s1和s2指向的是两个不同的对象,因此false
第二个
System.out.println(s1 == s5);//true
如果有 String s1 = "Programming";String s2 = "Programming";System.out.println(s1 == s2)
结果也是true,因为例子中的s1和s2中的"Programming”都是字符串常量,它们在编译期就被确定了,所以s1==s2为true;而"Program”和"ming”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中"Programming”的一个引用。所以也是true
第三个
System.out.println(s1 == s6);//false
如果有s1= "Program"+ "ming"
;那么这个就是true,但上面第三个是为什么是false呢?
这是因为字符串字面量拼接操作是在java编译期就执行了。也就是说编译期编译时,直接把program,ming字面量进行“+”操作得到一个"Programming"常量,并且直接将这个常量放入字符串池中,这样实际上是一种优化,将2个字面量合成一个,避免了创建多余的字符串对象,而字符串引用的+运算是在Java运行期间执行,即s3+s4在程序执行期间才进行计算,它会在堆内存中重新创建一个拼接后的字符串对象。总的来说“+”拼接是在编译期间进行的,拼接后的字符串存放在字符串池中;而字符串引起的+运算是在运行时进行的,新创建的字符串存放在堆中,直接相加效率高,间接相加效率比直接的低。
第四个
System.out.println(s1 == s6.intern());//true
、当s6调用intern的时候,会检查字符串池中是否含有该字符串。由于之前定义的s1已经进入字符串池中,所以会得到相同的引用。
第五个
System.out.println(s2 == s2.intern());//false
对比的是new的新的和s1相比,肯定为false