本文基于jdk8
使用双引号声明的字符串
使用双引号声明的字符串,先在常量池中查找。如果有相同的,就直接把引用返回;否则就在常量池中创建并返回引用
//因为用双引号声明的String对象会直接放在常量池中。
String s1 = "abc";//常量池中的引用
String s2 = "abc";//常量池中的引用
//使用双引号声明的字符串,先在常量池中查找,
//如果有相同的,就直接把引用返回,如果没有就在常量池中创建并返回引用
System.out.println(s1 == s2);//true
使用new关键字创建的字符串
采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有该字符串,如果有则在堆中创建对象返回堆中的引用;如果常量池中没有该字符串则先在常量池中创建字符串,之后在在堆中创建字符串对象,并返回堆中的引用。
//采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"xyz"这个字符串对象,
// 如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,
// 然后将堆中的这个"xyz"对象的地址返回赋给引用s3,
// 这样,s3就指向了堆中创建的这个"xyz"字符串对象;
// 如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,
// 然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用,
// 这样,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。
// s3 、s4是两个指向不同对象的引用,结果当然是false
String s3 = new String("xyz");//在常量池中创建xyz,在堆中创建对象并返回引用
String s4 = new String("xyz");//在堆中创建对象并返回引用
System.out.println(s3 == s4);//false
s.intern()的作用
如果常量池中没有该字符串,调用了该方法,会将常量池中开辟空间,里面保存堆中字符串的地址。
{
//在常量池中创建“1”字符串,并且在堆中创建字符串1对象,s1是堆中的引用
String s1 = new String("1");
String s3 = s1.intern(); //s3是常量池中的引用
String s2 = "1"; //s2是常量池中的引用
System.out.println(s1 == s2);//false
System.out.println(s2 == s3);//true
System.out.println(s1 == s3);//false
//第二种情况
// 第一个new String("1")先在常量池中创建“1”,在堆中创建“1”对象。
// 第二个new String("1")因为常量池中已经有“1”了,常量池中就不创建了,在堆中创建“1”;
// 因为用加号连接了所以在堆中还要创建“11”对象,s3是堆中的11对象
String s3 = new String("1") + new String("1");
// 常量池中没有11,先创建(并不是创建“11”,而是存储堆中的引用)再返回常量池中的引用。
String s5 = s3.intern();
String s4 = "11";//直接返回常量池的引用
System.out.println(s3 == s4);//true
// s3指向的是堆中的11对象
String s3 = new String("1") + new String("1");
// s5指向的常量池中的地址,该地址存的是堆中11对象的引用,
String s5 = s3.intern();
// s4指向常量池中的地址
String s4 = "11";
// 因为常量池的保存的是堆中的引用,三个变量指向是一样的
System.out.println(s5 == s3);//true
System.out.println(s5 == s4);//true
System.out.println(s3 == s4);//true
System.out.println("======================");
// String s6 = new String("go") +new String("od");
// String s7 = s6.intern();
// String s8 = "good";
// System.out.println(s6 == s7);//true
// System.out.println(s7 == s8);//true
// System.out.println(s6 == s8);//true
String s1 = "Hello";//直接在常量池中创建“hello”
//现在常量池中创建He,之后再堆中创建He
//之后在常量池中创建llo
//因为常量池中已经有hello了,所以不再常量池中创建了,直接在堆中创建hello;
String s2 = new StringBuffer("He").append("llo").toString();
String s3 = s2.intern();//返回常量池中的引用。
System.out.println("s1 == s2? " + (s1 == s2));//false
System.out.println("s1 == s3? " + (s1 == s3));//true
String m = "hello,world";
String n = "hello,world";
String u = new String(m);
String v = new String("hello,world");
System.out.println(m == u); //false m是常量池中的,u是堆中的,并不相等
System.out.println(u == v); //false u,v是堆中的不同对象,并不相等
// 发现原来是在JVM启动的时候调用了一些方法,在常量池中已经生成了"java"字符串常量,
// String s2 = new String("ja") + new String("va");
// String s3 = s2.intern();
// String s4 = "java";
// System.out.println(s2 == s3);//false
// System.out.println(s3 == s4);//true
}